Example:
type DefaultTheme = {
name: 'default';
colors: [string, string, string];
};
type CustomTheme = {
name: 'custom';
colors: [string, string, string, string, string];
};
type DefaultColor = ???; // 'default-1' | 'default-2' | 'default-3';
type CustomColor = ???; // 'custom-1' | 'custom-2' | 'custom-3' | 'custom-4' | 'custom-5';
The question is whether it's possible to use the length of the colors
array to create a mapped union type as in the given example.
The example is simplified for (hopefully) clarity, but in full there is a generic type Theme
that takes name
and length
arguments and uses length
to generate a tuple of fixed number of strings.
CodePudding user response:
I simplified @Aleksey L.'s solution a bit and took a different approach:
type Indices<T> = keyof T & `${number}`;
type Indices1<T extends [...any]> = Exclude<Indices<[...T, any]>, '0'>
type N_Test = Indices1<[string, string, string]> // '1' | '2' | '3'
type P_Test = `Test-${N_Test}`; // "Test-1" | "Test-2" | "Test-3"
Main differences:
- No use of ad-hoc mapped types
{ [key in ...]: ... }
- No recursive types (like in @kaja3's answer).
- No conditional types
X extends Y ? ... : ...
(Exclude
uses this internally, but it is a nice abstraction)
Applied to the example:
type DefaultTheme = {
name: 'default';
colors: [string, string, string];
};
type CustomTheme = {
name: 'custom';
colors: [string, string, string, string, string];
};
type WithPrefix<T extends {name: string, colors: string[]}> = `${T['name']}-${Indices1<T['colors']>}`;
type DefaultColor = WithPrefix<DefaultTheme>; // 'default-1' | 'default-2' | 'default-3';
type CustomColor = WithPrefix<CustomTheme>; // 'custom-1' | 'custom-2' | 'custom-3' | 'custom-4' | 'custom-5';
CodePudding user response:
For a non-evil solution, we can use a helper type which converts a tuple like [string, string, string]
into a union like 1 | 2 | 3
. This can be done recursively, using the length
property of the tuple.
type TupleToUnion<T extends any[]> =
T extends [any, ...infer R] ? T['length'] | TupleToUnion<R> : never
type GenerateUnion<T extends {name: string, colors: string[]}> =
`${T['name']}-${TupleToUnion<T['colors']>}`
// 'default-3' | 'default-2' | 'default-1'
type DefaultColor = GenerateUnion<DefaultTheme>
// 'custom-5' | 'custom-4' | 'custom-3' | 'custom-2' | 'custom-1'
type CustomColor = GenerateUnion<CustomTheme>
CodePudding user response:
Here's the evil