I have this static array that may grow over time. Eg maybe in a month I will add another entry.
const GROUPS = ['Objects', 'Things', 'Stuff']
All of these refer to an interface, such as
interface Group { name: string, level: number}
How do I make a TS type that maps it with only the allowed const strings?
type GroupType = {[key: GROUPS]: Group}
CodePudding user response:
First, in order for the compiler to keep track of the literal types of the elements of GROUPS
and not just string
, you should use a const
assertion when you initialize it:
const GROUPS = ['Objects', 'Things', 'Stuff'] as const;
// const GROUPS: readonly ["Objects", "Things", "Stuff"]
You can see that GROUPS
's type is now a readonly
tuple consisting of literal types.
Once you do that you can define GroupType
as a mapped type over the union of elements of the GROUPS
array, by indexing into the type typeof GROUPS
(using the typeof
type operator) with a number
index (since the type you get when accessing GROUPS[n]
where n
is of type number
is a union of the element types):
type GroupType = { [K in typeof GROUPS[number]]: Group }
/* type GroupType = {
Objects: Group;
Things: Group;
Stuff: Group;
} */
You could also write this out like:
type GROUPS = typeof GROUPS[number];
type GroupType = Record<GROUPS, Group>;
/* type GroupType = {
Objects: Group;
Things: Group;
Stuff: Group;
} */
where we give a type named GROUPS
to the element types of the GROUPS
value, and we use the Record<K, V>
utility type instead of the equivalent manually-written mapped type.