Search code examples
typescripttypestypeclasstypescript-genericstype-systems

I want to have a type that matches every single type of union type, but not any union of those single types


Let's suppose I have following types defined:

type A = {a:number};
type B = {a:string};
type C = {a:boolean};

type All = A | B | C;

Now I want to define generic type S (not using any of the types A,B and C in the definition) that behaves like that:

var a: S<A>;  // a is actually of type A
var b: S<B>;  // b is of type B
var c: S<C>;  // c is of type C
var all: S<All>; // all is of type never

To achieve that I can define S like that:

type S<T> = All extends T ? never : T;

However this is not sufficient for me because I also want that

var ab: S<A|B>; // ab should be type never but actually is A|B
var bc: S<B|C>; // bc should be type never but actually is B|C
var ca: S<C|A>; // ca should be type never but actually is C|A

Question

Given some union type, how to define generic type that can be matched to every single constituent of the union type, but can't be matched to any union of those constituents?

Solution should also work for union types with more than 3 constituents.


Solution

  • It seems that this does exactly what I want:

    type S<T> = [T] extends (T extends All ? [T] : never) ? T : never;