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