This syntax is invalid.
You need just replace blue
and green
with a union of all allowed colors:
type ColorNames = 'blue' | 'green'
type Variations = '' | 20 | 40 | 60 | 80;
type TAllColors<Color extends string> = {
[P in Variations as `${Color}${P}`]: string;
};
type Result = TAllColors<ColorNames>
type Colors = {
'blue': string;
'blue20': string;
'blue40': string;
'blue60': string;
'blue80': string;
'green': string;
'green20': string;
'green40': string;
'green60': string;
'green80': string;
}
// true
type IsCorrect =
Colors extends Result
? Result extends Colors
? true
: false
: false
Playground
What if green and blue have different variations ?
Then you need to create appropriate map data structure and iterate over newly created map and variations.
type ColorNames = 'blue' | 'green'
type VariationsBlue = '' | 10 | 20 | 30 | 40
type VariationsGreen = '' | 20 | 40 | 60 | 80;
type VariationsMap = {
blue: '' | 10 | 20 | 30 | 40;
green: '' | 20 | 40 | 60 | 80;
}
type NameConvert<T, V> =
T extends string
? V extends string | number
? `${T}${V}`
: never
: never
type TAllColors<Variations> = {
[V in keyof Variations]: {
[P in V as NameConvert<P, Variations[V]>]: string
}
}
type TransitionResult = TAllColors<VariationsMap>
Sush iteration produces two levels of nested properties.
type TransitionResult = {
blue: {
blue: string;
blue10: string;
blue20: string;
blue30: string;
blue40: string;
};
green: {
green: string;
green20: string;
green40: string;
green60: string;
green80: string;
};
}
We need somehow to obtain all values from above object and merge them. Retrieving all values is relatively easy:
type Values<T> = T[keyof T]
type TransitionResult = Values<{
blue: {
blue: string;
blue10: string;
blue20: string;
blue30: string;
blue40: string;
};
green: {
green: string;
green20: string;
green40: string;
green60: string;
green80: string;
};
}>
As you might have noticed we ended up with union of all values whereas we need an intersection.
type Values<T> = T[keyof T]
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Result = UnionToIntersection<Values<{
blue: {
blue: string;
blue10: string;
blue20: string;
blue30: string;
blue40: string;
};
green: {
green: string;
green20: string;
green40: string;
green60: string;
green80: string;
};
}>>
Whole code:
type ColorNames = 'blue' | 'green'
type VariationsBlue = '' | 10 | 20 | 30 | 40
type VariationsGreen = '' | 20 | 40 | 60 | 80;
type VariationsMap = {
blue: '' | 10 | 20 | 30 | 40;
green: '' | 20 | 40 | 60 | 80;
}
type NameConvert<T, V> =
T extends string
? V extends string | number
? `${T}${V}`
: never
: never
type TAllColors<Variations> = {
[V in keyof Variations]: {
[P in V as NameConvert<P, Variations[V]>]: string
}
}
type Values<T> = T[keyof T]
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Result = UnionToIntersection<Values<TAllColors<VariationsMap>>>
Playground