Typescript extract and create Union as a subset of a Union

Restricting a union to a subset of consituents is subtyping. In TypeScript, A extends B is a way of saying that A is a subtype of B. (This seems backwards to some people at some times; by removing elements from a union, you are making the type more specific, which is a subtype. The word "extends" might seem out of place, but that's what it is).

Unfortunately, you can't use extends to narrow type aliases the way you can with interfaces. What you'd like to do is use following invalid syntax:

// this is not valid TypeScript, do not use this:
type MySubUnion extends MyUnionType = 'foo' | 'bar'; // should work
type MySubUnion extends MyUnionType = 'foo' | 'bas'; // should fail

But you can't do that. As a workaround, you can make a new type function called Extends<T, U> which evaluates to U but only compile if U extends T, like this:

type Extends<T, U extends T> = U;

Then you can rewrite the invalid code to the following valid code:

type MySubUnion = Extends<MyUnionType, 'foo' | 'bar'>; // okay, compiles

and this:

type MySubUnion = Extends<MyUnionType, 'foo' | 'bas'>; // error:
// Type '"bas"' is not assignable to type 'MyUnionType'.

Does that help? Good luck!


You could always flip the declaration order, though it's a bit odd with the particular names here.

type MySubUnion = 'foo' | 'bar';
type MyUnionType = MySubUnion | 'baz';

It's more in the lines of composing union types.

Tags:

Typescript