TypeScript: Turn an Array of Values into a Type Union

I found the answer I was looking for here: https://dev.to/shakyshane/2-ways-to-create-a-union-from-an-array-in-typescript-1kd6

I wasn't sure that it would be possible. In fact, it turns out that the solution is far more impressive than I expected.

What follows cuts to the core part of the article that I need solved my particular problem.

Problem

I want to have an object type with specific keys and I want a static array of those keys, but I don't want to have the same list of keys written out twice in case I mistakenly make them differ in the future

type K = "a" | "b" | "c";
type O = Record<K, V>;
const keys: K[] = ["a","b","c"];

I want to be sure that 'keys' contains every member of type 'K' exactly once and vice-versa. I want to use 'keys' to build an object of type 'O', so I can't just rely on using 'Object.keys' on an existing object.

Solution

const keys = ["a","b","c"] as const;
type K = typeof keys[number];
type O = Record<K, V>;

Use 'as const' to make the type of  'keys' be interpreted as a readonly tuple of strings, whereas before it was an array, 'K[]', which could have any members of 'K' anywhere zero or more times each.

Because 'keys' is a value, it needs to be prefixed with 'typeof' to use its type in a type expression.

By indexing a tuple type with a specific number, you can get the type at that position in the tuple.

The incredible part: By indexing the tuple type with a union of numbers, you get the union of the types at those positions. Therefore by indexing 'typeof keys', which is a tuple, with 'number', which is the union of all numbers, you get the union of all strings in 'keys'.

type T = ["a", "b", "c"][0]; // "a"
type T = ["a", "b", "c"][0 | 1]; // "a" | "b"
type T = ["a", "b", "c"][number]; // "a" | "b" | "c"

Comments

Popular posts from this blog

Dynamically Update DNS When Your Server IP Address Changes

Use Joycons with Steam on Linux

In HTML, an Input with Zero Length is Never too Small