If I have a type like the below and I want to map it to some fixed values at compile time, I can do the following:
type MyType = {
a: string;
b: string;
}
const MyMapping: { [k in keyof MyType]: number } = {
a: 3,
b: 2,
}
type X = typeof MyMapping['a'] // Should be 3
Is there a way I can do the same for a union of existing types?
type MyType = {
a: string;
b: string;
}
const MyMapping: /* Magic type here */ = {
a: 3,
b: 2,
}
type X = typeof MyMapping['a'] // Should be 3
I realize this probably won't work in the exact form I have up there, but is there some other way to format this to make this happen?
First off, we can simplify
{[k in keyof MyType] : number}
to be justRecord<keyof MyType, number>
(basically the same type just using the predefined mapped typeRecord
)If you are using typescript 4.9 or later, you ca use the
satisfies
operator to constrain the type of the variable while still lettig the compiler infer the type. Coupled with anas const
to preserve the literal types, we get the desired result:Playground Link
If you are using a version of typescript before 4.9, you can still do this using an identity function to allow inference to happen but also constrain the type of the object literal:
Playground Link
There are a few tricks to the function:
V
type parameter is used to force TypeScript to infer number literals for the values in the object instead ofnumber
Record<Exclude<keyof T, keyof MyType>, never>
is used to prevent excess properties (this is because we don't get excess property checks when we assign to a type parameter)