Types, generics, narrowing and the utility types worth knowing.
Basic types
let name: string = 'Ada';
let count: number = 42;
let isActive: boolean = true;
let tags: string[] = ['a', 'b'];
let pair: [string, number] = ['x', 1];
let anything: unknown; // safer than any
function fail(): never { throw new Error(); }
Type vs interface
type Point = { x: number; y: number };
interface User { id: string; name: string }
interface Admin extends User { role: 'admin' }
type Status = 'idle' | 'loading' | 'done'; // unions: type only
Narrowing
function format(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value.toFixed(2);
}
if ('role' in user) { /* Admin */ }
if (error instanceof Error) { /* Error */ }
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value;
}
Generics
function first<T>(items: T[]): T | undefined {
return items[0];
}
function getProperty<T, K extends keyof T>(object: T, key: K): T[K] {
return object[key];
}
type ApiResponse<T> = { data: T; error?: string };
Utility types
| Type |
Result |
Partial<T> |
All properties optional |
Required<T> |
All properties required |
Readonly<T> |
All properties readonly |
Pick<T, 'a' | 'b'> |
Only the listed keys |
Omit<T, 'a'> |
All keys except the listed ones |
Record<K, V> |
Object with keys K and values V |
Exclude<U, X> |
Remove X from union U |
Extract<U, X> |
Keep only X from union U |
NonNullable<T> |
Remove null and undefined |
ReturnType<typeof fn> |
Return type of a function |
Parameters<typeof fn> |
Parameter tuple of a function |
Awaited<T> |
Unwrap a Promise type |
Const objects as source of truth
const ROLES = {
admin: 'Administrator',
editor: 'Editor',
viewer: 'Viewer',
} as const;
type Role = keyof typeof ROLES; // 'admin' | 'editor' | 'viewer'
type RoleLabel = (typeof ROLES)[Role];
const roleKeys = Object.keys(ROLES) as Role[];
Operators
| Syntax |
Meaning |
keyof T |
Union of keys of T |
typeof value |
Type of a value |
T[K] |
Indexed access type |
value as T |
Type assertion |
value! |
Non-null assertion |
value satisfies T |
Check type without widening |
T extends U ? X : Y |
Conditional type |
{ [K in keyof T]: X } |
Mapped type |
`prefix-${T}` |
Template literal type |