Is there a way to prevent union types in TypeScript? Is there a way to prevent union types in TypeScript? typescript typescript

Is there a way to prevent union types in TypeScript?


I am unsure what the usecase for this is, but we can force the NoUnion to never if the passed type is a union type.

As other mentioned conditional types distribute over a union, this is called distributive conditional types

Conditional types in which the checked type is a naked type parameter are called distributive conditional types. Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of T extends U ? X : Y with the type argument A | B | C for T is resolved as (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y).

The key there is 'naked type', if we wrap the type in a tuple type for example the conditional type will no longer be distributive.

type UnionToIntersection<U> =     (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never type NoUnion<Key> =    // If this is a simple type UnionToIntersection<Key> will be the same type, otherwise it will an intersection of all types in the union and probably will not extend `Key`    [Key] extends [UnionToIntersection<Key>] ? Key : never; type A = NoUnion<'a'|'b'>; // nevertype B = NoUnion<'a'>; // atype OtherUnion = NoUnion<string | number>; // nevertype OtherType = NoUnion<number>; // numbertype OtherBoolean = NoUnion<boolean>; // never since boolean is just true|false

The last example is an issue, since boolean is seen by the compiler as true|false, NoUnion<boolean> will actually be never. Without more details of what exactly you are trying to achieve it is difficult to know if this is a deal breaker, but it could be solved by treating boolean as a special case:

type NoUnion<Key> =    [Key] extends [boolean] ? boolean :    [Key] extends [UnionToIntersection<Key>] ? Key : never;

Note: UnionToIntersection is taken from here


By the way, the "simpler" one I was trying to come up with looks like this:

( NOTE: the following doesn't work in TS after v3.3, due to microsoft/TypeScript#34504:

// type NotAUnion<T> = [T] extends [infer U] ? //  U extends any ? [T] extends [U] ? T : never : never : never;

instead one can use the following since defaults still get instantiated before distribution, at least for now: )

type NotAUnion<T, U = T> =  U extends any ? [T] extends [U] ? T : never : never;

This should work (please test it; not sure why I got the original version in my answer to another question wrong but it's fixed now ). It's a similar idea to the UnionToIntersection: you want to make sure that a type T is assignable to each part of T if you distribute it. In general that's only true if T is a union with just one constituent part (which is also called "not a union").

Anyway, @TitianCernicovaDragomir's answer is perfectly fine also. Just wanted to get this version out there. Cheers.


This also works:

type NoUnion<T, U = T> = T extends U ? [U] extends [T] ? T : never : never;