Description
openedon Jan 5, 2017
A suggestion to create a runtime array of union members was deemed out of scope because it would not leave the type system fully erasable (and because it wouldn't be runtime complete, though that wasn't desired). This suggestion is basically a variant of that one that stays entirely within the type domain, and thus stays erasable.
The suggestion is for a keyword similar to keyof
that, when given a union type, would result in a tuple type that includes each possibility in the union.
Combined with the suggestion in this comment to instead implement a codefix to create the array literal, this could be used to ensure that 1. the array was created correctly to begin with, and 2. that any changes to the union cause an error requiring the literal array to be updated. This allows creating test cases that cover every possibility for a union.
Syntax might be like this:
type SomeUnion = Foo | Bar;
type TupleOfSomeUnion = tupleof SomeUnion; // has type [Foo, Bar]
type NestedUnion = SomeUnion | string;
type TupleOfNestedUnion = tupleof NestedUnion; // has type [Foo, Bar, string]
Some issues I foresee:
-
I don't know what ordering is best (or even feasible), but it would have to be nailed down in some predictable form.
-
Nesting is complicated.
-
I expect generics would be difficult to support?
-
Inner unions would have to be left alone, which is somewhat awkward. That is, it would not be reasonable to turn
Wrapper<Foo|Bar>
into[Wrapper<Foo>, Wrapper<Bar>]
even though that might (sometimes?) be desirable. In some cases, it’s possible to use conditional types to produce that distribution, though it has to be tailored to the particularWrapper
. Some way of converting back and forth betweenWrapper<Foo|Bar>
andWrapper<Foo>|Wrapper<Bar>
would be nice but beyond the scope of this suggestion (and would probably require higher-order types to be a thing). -
My naming suggestions are weak, particularly
tupleof
.
NOTE: This suggestion originally also included having a way of converting a tuple to a union. That suggestion has been removed since there are now ample ways to accomplish that. My preference is with conditional types and infer
, e.g. ElementOf<A extends unknown[]> = A extends (infer T)[] ? T : never;
.