TS union from constants in a JS file

Do you have a file containing constants that you'd like to create a string union from? Here's how you can do that.

Reading Time
2 min (~238 words)
Tags
Typescript
Date
2/18/2022
TS union from constants in a JS file

The problem: You have a file containing many constants that you'd like to create a string union from the names or values of.

The solution: Use keyof and typeof to create a union from the keys and values of an object.

Example
#

in constaints.ts

1export const MY_NAME = 'Trevor';
2export const I_LIKE = 'Music';
3export const MY_CAT = 'IS_CUTE';

in some other typescript file:

1import * as Constants from './constants';
2
3type ValueOf<T> = T[keyof T];
4
5// 'MY_NAME' | 'I_LIKE' | 'MY_CAT';
6export type KeyUnionOfConstants = keyof typeof Constants;
7
8// 'Trevor' | 'Music' | 'IS_CUTE';
9export type ValueUnionOfConstants = ValueOf<typeof Constants>;

Tada!

Explanation
#

But why does this work?

import * as Constants from './constants';

imports each export from constants.ts as a key/value pair in an object that looks like this:

1{
2  MY_NAME: 'Trevor',
3  I_LIKE: 'Music',
4  MY_CAT: 'IS_CUTE'
5}

typeof Constants is just that object expressed as a type, which looks identical.

1type Constants = {
2  MY_NAME: 'Trevor';
3  I_LIKE: 'Music';
4  MY_CAT: 'IS_CUTE';
5}

keyof typeof Constants is each unique key in that type: MY_NAME, I_LIKE, and MY_CAT.

ValueOf is slightly more complicated, but essentially it's a way of saying "Get each key from some type called T, and use it to get the value inside T" or another way of thinking about it:

1Object.values({
2  MY_NAME: 'Trevor',
3  I_LIKE: 'Music',
4  MY_CAT: 'IS_CUTE'
5}); // ['Trevor', 'Music', 'IS_CUTE']

ValueOf is doing something similar but with type information instead of actual runtime values. 'Give me the values contained inside a given object generically represented as T'.