Static typing, interfaces, generics, and decorators.
Primitives & Literalstype Dir = "north" | "south" | "east" | "west"; let d: Dir = "north";type vs interfaceinterface User { id: number; name: string; } // can be extended elsewhereIntersection types (A & B)type AdminUser = User & { permissions: string[]; auditLog: AuditEntry[]; };Union types (A | B)type Result = { ok: true; data: User } | { ok: false; error: string };Discriminated unionstype Event = {type:'click';x:number} | {type:'key';key:string}; // switch(e.type)Tuple typestype RGB = [r: number, g: number, b: number]; const red: RGB = [255, 0, 0];Enums vs const enums / as constconst STATUS = { ACTIVE: 'active', PENDING: 'pending' } as const; type Status = typeof STATUS[keyof typeof STATUS];never typefunction assertNever(x: never): never { throw new Error('Unexpected: ' + x); }Generic functionsfunction first<T>(arr: T[]): T | undefined { return arr[0]; }Generic constraints (extends)function getLen<T extends { length: number }>(x: T): number { return x.length; }Default type parameterstype ApiResponse<T = unknown> = { data: T; status: number; }; Conditional types (T extends U ? X : Y)type IsArray<T> = T extends any[] ? true : false;infer keywordtype UnwrapPromise<T> = T extends Promise<infer U> ? U : T;Mapped typestype Optional<T> = { [K in keyof T]?: T[K] }; // makes all props optionalTemplate literal typestype EventName<T extends string> = `on${Capitalize<T>}`; type ClickEv = EventName<"click">; // "onClick"Partial<T> / Required<T>function updateUser(id: number, patch: Partial<User>): Promise<User>Readonly<T>const config: Readonly<Config> = Object.freeze({ port: 3000 });Pick<T, K> / Omit<T, K>type PublicUser = Omit<User, 'password' | 'internalNotes'>; Record<K, V>const cache: Record<string, User> = {}; const roles: Record<'admin'|'user', Permission[]> = {...};ReturnType<T> / Parameters<T>type Handler = (req: Request) => Response; type Req = Parameters<Handler>[0];Awaited<T>type UserData = Awaited<ReturnType<typeof fetchUser>>;Extract<T,U> / Exclude<T,U>type StringOrNum = string | number | boolean; type OnlyStr = Extract<StringOrNum, string>;typeof / instanceofif (typeof x === 'string') x.toUpperCase(); if (x instanceof Date) x.getTime();in operator narrowingif ('data' in result) console.log(result.data); // result is success typeType predicates (x is T)function isUser(x: unknown): x is User { return typeof x === 'object' && x !== null && 'id' in x; }Assertion functionsfunction assertDefined<T>(val: T): asserts val is NonNullable<T> { if (!val) throw new Error('Null!'); }satisfies operatorconst palette = { red: [255,0,0], blue: '#0000ff' } satisfies Record<string, string|number[]>;as const assertionconst routes = ['/home', '/about', '/contact'] as const; // readonly ["/home", "/about", "/contact"]Class decorators@injectable() @singleton() class UserService { constructor(@inject('DB') private db: Database) {} }@Input() / @Output() style@Controller('/users') class UsersCtrl { @Get('/:id') find(@Param('id') id: string) {} }Declaration files (.d.ts)declare module 'old-lib' { export function doThing(x: string): number; }tsconfig strict: true{ "compilerOptions": { "strict": true, "target": "ES2022", "moduleResolution": "bundler" } }Path aliases"paths": { "@/*": ["./src/*"] } // then import { auth } from '@/services/auth'