Avoiding unintended undefined values while using TypeScript Record
sarioglu
Posted on February 28, 2021
If you are already familiar with TypeScript, you must know that it provides different ways to type objects. You can use a type
or an interface
to strongly type your objects:
type MyObject = {
foo: string;
bar: boolean;
};
interface MyObject {
foo: string;
bar: boolean;
}
Sometimes we also use objects as key-value stores where we don't know their properties beforehand. In such cases Record
utility type provided by TypeScript comes in handy:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
There's a catch though. If you use string
as its key, TypeScript will assume that your object holds a value for every possible string
. Consider the following example for clarity:
type Colors = Record<string, string>;
const colors: Colors = {
red: "#FF0000",
green: "#00FF00",
blue: "#0000FF"
};
console.log(colors.red); // "#FF0000"
console.log(colors.yellow); // undefined
As you can see, TypeScript gives no error for colors.yellow
and expects that it is a string
. However it is not. We don't have a value for yellow
in our object. This is especially dangerous if you try to reach to a property of value. In such case we may have Uncaught TypeError
exception and our application may crush.
console.log(colors.red.toLowerCase()); // "#ff0000"
console.log(colors.yellow.toLowerCase()); // Uncaught TypeError: can't access property "toLowerCase" of undefined
Solution: Use Partial
To avoid such cases, we can combine Record
with another utility type, Partial
:
type Colors = Partial<Record<string, string>>;
Now we can use our Colors
type safely and let TypScript to warn us about possible type errors.
Posted on February 28, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024