I need to create a Typescript Record
with the keys defined in an independent type and specific types for each value.
The keys are defined as follows:
// Keys must be available/iterable at runtime
const keys = ['a', 'b', 'c'] as const
export type Key = typeof keys[number]
Now I see two options, both flawed.
Option 1: repeat the keys and define the value types explicitly, as needed. Flaw: Structure
isn't actually based on Key
and they might deviate.
export type Structure1 = {
a: number
b: boolean
c: string
}
Option 2: define a record from Key
and lose the specific type information on the values:
export type Structure2 = Record<Key, number | boolean | string>
Is there a third option for a Structure3
that uses Key
as the key type and an explicit value type per key?
CodePudding user response:
You can keep it DRY and enforce your interface keys like this (performance bonus: no extra runtime code):
type EnforceKeys<Key extends string, T extends Record<Key, unknown>> = {
[K in keyof T as K extends Key ? K : never]: T[K];
};
const keys = ['a', 'b', 'c'] as const;
type Key = typeof keys[number];
// Ok
type Structure1 = EnforceKeys<Key, {
a: number;
b: boolean;
c: string;
}>;
// Ok, and extra properties are omitted
type Structure2 = EnforceKeys<Key, {
a: number;
b: boolean;
c: string;
d: number[]; // omitted from type
e: boolean; // omitted from type
}>;
// Error: Property 'c' is missing in type... (2344)
type Structure3 = EnforceKeys<Key, {
a: number;
b: boolean;
}>;