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.
Top comments (0)