I have a union of types and I’d like to create a utility type that creates a non mixed array type from it, e.g.:
type MyType = string | number
type ArrayOfMyType = ToArray<MyType> // -> string[] | number[], but not (string | number)[]
I was curious about the solution proposed by Lishugupta652. Even if it is clearly AI generated it works and i think it is more important to understand why than just paste some snippet and expect the answer to be accepted.
The way it works has something to do with type distribution, which is defined like this in this article :
Type distribution […] is a feature of a compiler that applies
conditionals to each item of generic union types, not to a union as a
whole.
If we use a generic union type directly to construct a new type, like in this example :
type ToArray<T> = T[];
type MyArray = ToArray<string | number>
T[]
will result to (string | number)[]
because the whole union type is used, regardless of the items it contains
Here comes the extends
property. Using extends
will apply the condition on each items, where T
will be the current iteration. The type is being distributed, therefore we can construct the wanted type
type ToArray<T> = T extends unknown ? T[] : never;
type MyArray = ToArray<string | number> // string[] | number[]
There is indeed one exception with the boolean type (i searched if there was another but apparently), because a boolean works like a literal type containing two value, true
and false
, therefore if we distribute the generic union type, we will get one iteration for the type true
and one for the type false
. So for this specific case adding an exception works
type ToArray<T> = T extends boolean ? boolean[] : T extends any ? T[] : never;
type ArrayOfMyType = ToArray<string | number| boolean>; // string[] | number[] | boolean
For both types true
and false
the returned type will be boolean[]
, because for both of them extends boolean ?
will be true
1
type MyType = string | number;
type ToArray<T> = T extends boolean ? boolean[] : T extends any ? T[] : never;
type ArrayOfMyType = ToArray<MyType>; // string[] | number[]
typescript playground
5