type Human = {
name: string;
age: number;
}
which also enforces value types in the compiler, rather than requiring runtime guards. type Human = {
name: string;
age: number;
}
which also enforces value types in the compiler, rather than requiring runtime guards. // ... other code
type Human = { name: string; age: number }
const isHuman = (obj: unknown): obj is Human => obj && typeof obj === 'object' && 'name' in obj && 'age' in obj; // you can complete the gaps here and also check the property types
someArray.filter(isHuman).forEach((h) => {
// h has type Human now
console.log(h.age);
})type Tips = { [tipGuid: string]: TipObject }
which can be rewritten using Record as
type Tips = Record<string, TipObject>
That pattern ins't very useful when creating object with known keys but for data structures where the key is either not known or generated it a godsend.
type Tips = Record<string, TipObject>
const tips: Tips = {}
tips["hello"] // TipObject, but you actually get undefined
It's better to define a Dictionary type like so: type Dictionary<K extends string | number | Symbol, V> = Partial<Record<K, V>>
Then to use: type Tips = Dictionary<string, TipObject>
const tips: Tips = {}
tips["hello"] // TipObject | undefined
That way, you're always forced to check for existence, and you never accidentally attempt to access properties on `undefined`. const todos: string[] = [“walk dog”];
todos[123].toUpperCase() // error!
IMO non constant (as defined by TypeScript) arrays should’ve been automatically assigned a union type with `undefined`, which can also be a fix for Records too: type Tips = Record<string, TipObject | undefined> type Tips = Record<“foo”, TipObject>;
const tips: Tips = {}; // error, needs key “foo”
tips["foo"]; // fine
tips["bar"]; // error, no key “bar” in tips
It’s worth mentioning that this isn’t just an issue with objects. For example, by default, the index type on arrays is unsafe: const arr: number[] = [];
const first: number = arr[0]; // actually undefined, but typescript allows it
If you do need an index type and want to account for undefined keys, the idiomatic way is the noUncheckedIndexAccess compiler flag [2], which will automatically make any index property access a union with undefined.[1] https://www.typescriptlang.org/docs/handbook/2/objects.html#...
[2] https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAc...
Internally in the backend, you’d still use the type you just posited.
On review of documentation, I was actually pretty off base in grandparent comment. The real use case for Record appears to be when you need a map type whose keys are both explicitly enumerated and defined elsewhere, ie in a union, enum, or otherwise unrelated object type. Rather than duplicating the keys, you can use Record<someUnion, V> or Record<keyof typeof someEnum, V> and only have to make one change to update both.
For the "arbitrary keys, known value types" case I mentioned earlier, an object type with an index signature works fine and may be more legible.
If I understand you correctly, that's exactly what a Record is underneath