Reputation: 2210
If I have a TypeScript type alias defined like this:
export type PlatformType = 'em' | 'ea' | 'hi';
how can I declare a property in an interface so that that property is an array of exactly one type of each PlatformType
alias? For example, I want this:
export interface Constants {
platformTypes: PlatformType[]; // how to declare a type for platformTypes?
}
so that when I have an object of Constants
type, I need to have this:
export const constants: Constants = {
platformTypes: ['em', 'ea', 'hi']
}
Basically, I would like to get an error if I have this:
export const constants: Constants = {
platformTypes: ['em', 'ea'] // should error, missing 'hi'
}
or
export const constants: Constants = {
// this will error anyway because 'extra' doesn't belong to PlatformType alias
platformTypes: ['em', 'ea', 'hi', 'extra']
}
or
export const constants: Constants = {
platformTypes: ['em', 'em', 'ea', 'hi'] // should error, duplicate 'em'
}
Upvotes: 4
Views: 445
Reputation: 33111
I think you should define a permutation of all allowed tuples.
For instance, if you have a union of three elements you need to create at least 6 tuples:
["em", "ea", "hi"] | ["em", "hi", "ea"] | ["ea", "em", "hi"] | ["ea", "hi", "em"] | ["hi", "em", "ea"] | ["hi", "ea", "em"]
This is because union is unordered data structure.
export type PlatformType = 'em' | 'ea' | 'hi';
// credits goes to https://twitter.com/WrocTypeScript/status/1306296710407352321
type TupleUnion<U extends string, R extends any[] = []> = {
[S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
}[U];
export interface Constants {
platformTypes: TupleUnion<PlatformType>; // how to declare a type for platformTypes?
}
export const constants: Constants = {
platformTypes: ['em', 'ea', 'hi'] // ok
}
export const constants2: Constants = {
platformTypes: ['em', 'ea'] // error
}
export const constants3: Constants = {
platformTypes: ['em', 'ea', 'hi', 'extra'] // error
}
export const constants4: Constants = {
platformTypes: ['em', 'em', 'ea', 'hi'] // error
}
Please keep in mind, that order of unions in typescript is tricky. Please see this question and this issue
You can find more examples in my blog
Upvotes: 1