Reading — step 1 of 5
Learn
~1 min readType-Level Programming
Template literal types let you compose string literal types using template syntax. Compile-time string manipulation.
type Greeting = `hello, ${string}`;
const a: Greeting = 'hello, world'; // OK
const b: Greeting = 'hi there'; // Error
The placeholder can be specific:
type Color = 'red' | 'green' | 'blue';
type HexColor = `#${string}`;
type CssVariable = `--${string}`;
type EventName = `on${Capitalize<string>}`;
const evt: EventName = 'onClick'; // OK
Combinatorial expansion — string unions multiply:
type Verb = 'get' | 'set' | 'delete';
type Resource = 'user' | 'post' | 'comment';
type Action = `${Verb}_${Resource}`;
// 'get_user' | 'get_post' | 'get_comment' | 'set_user' | ... (9 combinations)
Built-in string transformations:
Uppercase<T>,Lowercase<T>Capitalize<T>,Uncapitalize<T>
Pattern matching with infer in template types:
type HttpMethod<T> = T extends `${infer M} ${string}` ? M : never;
type A = HttpMethod<'GET /users'>; // 'GET'
type B = HttpMethod<'POST /api'>; // 'POST'
The infer M captures the part before the space.
Practical use case — typed event names:
type EventMap = {
click: { x: number; y: number };
hover: { id: string };
keyup: { key: string };
};
type Handler<E extends keyof EventMap> = (event: EventMap[E]) => void;
function on<E extends keyof EventMap>(name: E, handler: Handler<E>) {
// ...
}
on('click', e => console.log(e.x, e.y)); // typed
on('hover', e => console.log(e.id)); // typed
on('unknown', () => {}); // ERROR — not a key
Combined with key remapping — type-safe APIs:
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…