π· TypeScript Patterns β
Leveraging TypeScript's type system for safer, more expressive code.
Essential types β
typescript
// Union types
type Status = 'pending' | 'active' | 'archived'
// Discriminated unions
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string }
// Utility types
Partial<T> // All properties optional
Required<T> // All properties required
Pick<T, K> // Select specific properties
Omit<T, K> // Exclude specific properties
Record<K, V> // Object with typed keys and valuesType narrowing β
typescript
function handle(input: string | number) {
if (typeof input === 'string') {
// TypeScript knows input is string here
return input.toUpperCase()
}
return input * 2
}Generics β
typescript
// Generic function
function first<T>(arr: T[]): T | undefined {
return arr[0]
}
// Generic with constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}Zod for runtime validation β
typescript
import { z } from 'zod'
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
})
type User = z.infer<typeof UserSchema>
// Validates at runtime AND infers types
const user = UserSchema.parse(requestBody)Best practices β
- Prefer
typeoverinterfacefor unions and intersections - Use
interfacefor extendable contracts (classes, APIs) - Avoid
anyβ useunknownand narrow - Use
as constfor literal types - Enable
strictmode in tsconfig - Don't over-type β let TypeScript infer when it can
Anti-patterns β
anyeverywhere (defeats the purpose)- Type assertions (
as) to silence errors instead of fixing them - Excessively deep generic types that are hard to read
- Duplicating types instead of deriving them