When dealing with union types in TypeScript, it can be challenging to create a numeric literal type that represents the number of members in a scalable way. Due to the lack of direct access to this information, manipulating unions becomes necessary. However, TypeScript does not support observing any particular order for unions (e.g., A | B
being equivalent to B | A
). This leaves developers with two less-than-ideal options: iterate over every ordering of the union (which scales poorly) or resort to unsupported tricks as discussed in "How to transform union type to tuple type". It is generally best to avoid these approaches, especially if there is control over the union's source.
An easier alternative involves starting with tuple types, which arrange the elements of the union in a specific order. For example:
type TupleOfThree = ["a", "b", "c"];
type TupleOfFive = [1, 2, 7, 15, 23];
Tuple types represent arrays with known lengths and orders. They are essentially specialized versions of standard array types like Array
, containing familiar methods such as map()
, filter()
, and length
. By creating an array of type TupleOfThree
, indexing into it using a numerical key will yield a value corresponding to the union members. Similarly, accessing the length property of a value of type TupleOfThree
will reveal the numeric literal type of its union size.
Assuming each element in the tuple corresponds to a single union member and no intentional deviations are made (e.g., mixing literals with unions), this method offers a straightforward solution:
const randomSet: Set<TupleOfThree[number]> = new Set();
const size: TupleOfThree["length"] = 3; // works fine
if (randomSet.size === size) {
console.log('the set is full!');
}
Editing TupleOfThree
to add more members would trigger a compile-time error:
type TupleOfThree = ["a", "b", "c", "d"]; // additional member "d"
const randomSet: Set<TupleOfThree[number]> = new Set();
const size: TupleOfThree["length"] = 3; // error!
// ~~~~ <--- Type '3' is not assignable to type '4'.
To explore this concept further and experiment with the code, check out the playground link provided.