TS Examples
A grab-bag of small, real TypeScript patterns you can paste into the editor and adapt.
Typed fetch wrapper
TS
async function json<T>(input: RequestInfo, init?: RequestInit): Promise<T> {
const res = await fetch(input, init);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json() as Promise<T>;
}
type User = { id: number; name: string };
const u = await json<User>('/api/users/1');
Result type (Rust-flavoured)
TS
type Result<T, E = string> =
| { ok: true; value: T }
| { ok: false; error: E };
function parseId(s: string): Result<number> {
const n = Number(s);
return Number.isInteger(n)
? { ok: true, value: n }
: { ok: false, error: `not an int: ${s}` };
}
Tiny EventEmitter
TS
type Events = {
login: { user: string };
logout: void;
error: { code: number; message: string };
};
class TypedEmitter<E> {
private listeners = new Map<keyof E, Set<(arg: any) => void>>();
on<K extends keyof E>(event: K, fn: (arg: E[K]) => void) {
if (!this.listeners.has(event)) this.listeners.set(event, new Set());
this.listeners.get(event)!.add(fn as any);
}
emit<K extends keyof E>(event: K, arg: E[K]) {
this.listeners.get(event)?.forEach(fn => fn(arg));
}
}
const bus = new TypedEmitter<Events>();
bus.on('login', e => console.log(e.user)); // typed!
Type-safe deep get
TS
function get<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const u = { id: 1, name: 'Ada' };
const id = get(u, 'id'); // number
// const z = get(u, 'foo'); // ✗ error
Branded type for IDs
TS
type UserId = number & { readonly __brand: 'UserId' };
type PostId = number & { readonly __brand: 'PostId' };
function fetchUser(id: UserId) { /* ... */ }
const a = 1 as UserId;
fetchUser(a);
const b = 1;
// fetchUser(b); // ✗ — plain number can't masquerade as UserId
Exhaustive switch
TS
type Shape =
| { kind: 'circle'; r: number }
| { kind: 'rect'; w: number; h: number };
function area(s: Shape): number {
switch (s.kind) {
case 'circle': return Math.PI * s.r ** 2;
case 'rect': return s.w * s.h;
default: {
const _: never = s;
throw new Error('unhandled');
}
}
}
Tip: Whenever you find a pattern useful, save it as a snippet in your editor. A small personal library of TypeScript patterns is one of the highest-leverage things you'll build.
Example
Example
// A few patterns to paste into the editor:
// 1. typed reduce
const sum = [1, 2, 3].reduce<number>((c, n) => c + n, 0);
// 2. Discriminated union
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
// 3. Generic constraint
function key<T extends object>(o: T): keyof T { return Object.keys(o)[0] as keyof T; }
console.log(sum, key({ a: 1, b: 2 }));
Try it Yourself »
Exercise
Pattern for "value tagged as a brand" — phantom property name typical convention.
type UserId = number & { readonly
__: 'UserId' };
Five letters.
Discussion
Loading…