A new feature in TypeScript 4.1 is the ability to create Template Literal Types. This feature allows you to use string interpolation to create types:
type World = "world";
type HelloWorld = `Hello ${World}`;
// type HelloWorld = "Hello world"
Looks interesting, right? This feature gets even more powerful when you combine it with union string literals:
type Vertical = "top" | "middle" | "bottom";
type Horizontal = "left" | "center" | "right";
type Position = `${Vertical}-${Horizontal}`;
declare function setPosition(pos: Position): void;
setPosition("top-right");
setPosition("bottom-left");
The union types are expanded to include every possible permutation! So we get access to top-center
, bottom-right
, top-left
, and so on, and all the type safety that this brings. Hopefully you can see the potential here. For example, we can easily expand on this to add more options—I'm English, so we could add "centre" to the Horizontal
type to enable a bit of localisation.
This example was lifted straight from the TypeScript release notes for Version 4.1, but I wanted to see what else I could come up with. Below is an example of using template literal types to create hex pairs, which we can then use in a makeColor function:
type HexNum = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type HexLet = "a" | "b" | "c" | "d" | "e" | "f";
type HexChar = HexNum | HexLet;
type HexPair = `${HexChar}${HexChar}`
// Stub
type Color = {};
declare function makeColor(r: HexPair, g: HexPair, b: HexPair, a?: HexPair): Color;
makeColor("aa", "1a", "ff");
makeColor("ba", "da", "55", "e5");
makeColor("zz", "vv", "1j"); // error!
Here, we define all the possible hex characters, and then define a HexPair
by using template literal types to join two HexChar
s together. We then use this type for each argument to the makeColor function, to enable type safety when passing in a hex pair.
Pretty neat!
Note: There's an upper limit on the size of a union type generated this way. For example, I tried joining my HexPair
type three times to create a RGBColor
type, but got a Expression produces a union type that is too complex to represent.
error.
The code in this post is available in this TypeScript Playground.
Top comments (1)
An explanation of the limitation can be found here:
stackoverflow.com/a/65341336