String union types are convenient, but creating type guards for them without repetition isn’t immediately obvious. This post explains how to create DRY type guards for string union types in TypeScript.
We use string union types in various places throughout Qualdesk. They’re easy to read, easy to update, and because they’re strings, they’re useful when you need to specify things like CSS classnames.
To refresh your memory, a string union type looks like this:
If we want to:
- check that a string is a
- narrow the type of the string to
we need to write a user-defined type guard.
For example, a simple type guard for ‘red’ might look like this:
What if we want to check if a string is any one of the valid color keys?
We could do something like this:
but then we’ve just repeated the entire type definition in the type guard function.
In this situation, if we add a new color, we have to update both the type and the type guard.
There’s an alternative.
First, we need to define an array of colors:
You’ll notice that there’s
as const at the end of this definition. This defines
COLORS as a readonly array consisting of precisely the values in the declaration.
This is important in the next step, definining the
ColorKey type itself:
What does this do? It tells the compiler that
ColorKey is the type of any of the elements in
COLORS. An ‘any of’ type is a union type, and so we end up with the
ColorKey type definition exactly as we did above.
If we didn’t cast the
as const, the type of each of the elements in
COLORS would simply be
string, and so we’d end up with
ColorKey === string: not very helpful.
Finally, we can rewrite the type guard using the
Now we have a DRY type guard. If we want to add a new color, we just add it to the array, and the type guard will recognize it immediately.