Given the following list:
const list = ["A", "B", "C"] as const;
type List = typeof list[number];
I have a map that must have all of the possible keys of list
:
const mapping: Record<List, unknown> = {
A: true,
B: 2,
C: "three"
};
Just like I could enforce mapping
to map over List
, I would like to do the same for a type. Something like this (I'm aware it's an invalid syntax):
type MappedList: Record<List, unknown> = {
A: boolean,
B: number,
C: string
}
My main goal is to prevent a situation when I add a new cell into list
and forget to add it to MappedList
.
See playground
AFAIK, there is not such concept as type for type. However, you can use mapped types to create one type from another.
const list = ["A", "B", "C"] as const;
type ListKey = typeof list[number];
// type MappedList = {
// A: "property";
// B: "property";
// C: "property";
// }
type MappedList = {
[Prop in ListKey]: 'property'
}
As far as I understood, you also need to assure that A
is a boolean
, B
is a number
and C
is a string
. In order to do it, you need create a map and conditional type:
const list = ["A", "B", "C"] as const;
type ListKey = typeof list[number];
type TypeMap = {
A: boolean,
B: number,
C: string
};
/**
* If T is a subtype of TypeMap
* and keyof T extends keyof TypeMap
*/
type BuildMappedList<T> = T extends TypeMap ? keyof T extends keyof TypeMap ? T : never : never;
/**
* Ok
*/
type MappedList = BuildMappedList<{
A: true,
B: 2,
C: "three",
}>
/**
* Never
*/
type MappedList2 = BuildMappedList<{
A: true,
B: 2,
C: "three",
D: [2] // because of extra D property
}>
/**
* Never
*/
type MappedList3 = BuildMappedList<{
B: 2,
C: "three",
}> // because no A property
/**
* Never
*/
type MappedList4 = BuildMappedList<{
A: false,
B: [2], // because B is not a number
C: "three",
}>
enter link description here
You can do this by creating a utility that would require generics to match:
type AssertKeysEqual<
T1 extends Record<keyof T2, any>,
T2 extends Record<keyof T1, any>
> = T2
const list = ["A", "B", "C"] as const;
type ListKey = typeof list[number];
const mapping: Record<ListKey, unknown> = {
A: true,
B: 2,
C: "three",
};
type MappedList = AssertKeysEqual<Record<ListKey, unknown>, {
A: boolean;
B: number;
C: string;
}>
Typescript playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With