I have the following Union type;
type MyUnionType = 'foo' | 'bar' | 'baz'
I would like to create a new Union MySubUnion
as a subset;
type MySubUnion = 'foo' | 'bar'
I would like MySubUnion
to be constrained to the values of its parent MyUnionType
type MySubUnion = 'foo' | 'bas' // => Error Type String 'b...
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.
Use the Exclude<Type, Union> utility type.
type MyUnionType = 'foo' | 'bar' | 'baz'
type SubType = Exclude<MyUnionType, 'baz'>
// SubType is now 'foo' | 'bar'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With