In this blog post, we use TypeScript to ensure that an object stays in sync with an Array that lists its properties.
Consider the following TypeScript code:
interface Person {
first: string;
last: string;
}
const personKeys = [
'first',
'last',
] as const;
personKeys
lists the property keys of Person
. Can we check at compile time if this list is correct?
import {assert as tsafeAssert, Equals} from 'tsafe';
tsafeAssert<Equals<
keyof Person,
(typeof personKeys)[number]
>>();
Library tsafe
enables us to check if two types are equal.
The arguments of Equals<>
are computed as follows:
// %inferred-type: "first" | "last"
type A = keyof Person;
// %inferred-type: readonly ["first", "last"]
type B = typeof personKeys;
// %inferred-type: "first" | "last"
type C = B[number];
To compute type C
, we are using the indexed access operator T[K]
: For a given type T
, it computes the types of all properties whose keys are assignable to type K
. The following two types are roughly equivalent. That explains the result of computing B[number]
.
type T = ["first", "last"];
type U = {
0: "first",
1: "last",
};
T[K]
” in “Tackling TypeScript”