# Mastering TypeScript: Advanced Patterns for Production Code
TypeScript has revolutionized how we write JavaScript, bringing type safety and better developer experience. Let me share some advanced patterns I use in production.
Discriminated Unions
One of my favorite TypeScript features is discriminated unions. They're perfect for modeling state machines and API responses.
type Result<T, E = Error> =
| { status: 'success'; data: T }
| { status: 'error'; error: E }
| { status: 'loading' }function handleResult<T>(result: Result<T>) {
switch (result.status) {
case 'success':
return result.data // TypeScript knows this exists!
case 'error':
return result.error // And this too!
case 'loading':
return null
}
}
Generic Constraints
Generics become powerful when combined with constraints. This ensures type safety while maintaining flexibility.
interface HasId {
id: string
}function findById<T extends HasId>(items: T[], id: string): T | undefined {
return items.find(item => item.id === id)
}
Utility Types
TypeScript's built-in utility types are incredibly useful. Here are my most-used ones:
- Partial<T>: Makes all properties optional
- Required<T>: Makes all properties required
- Pick<T, K>: Creates a type with only specified properties
- Omit<T, K>: Creates a type without specified properties
- Record<K, T>: Creates an object type with specified keys and values
Type Guards
Custom type guards help TypeScript understand your runtime checks:
function isString(value: unknown): value is string {
return typeof value === 'string'
}function processValue(value: unknown) {
if (isString(value)) {
// TypeScript knows value is string here
return value.toUpperCase()
}
}
Conclusion
These patterns have saved me countless hours of debugging and made my code more maintainable. TypeScript is not just about adding types—it's about making your code more expressive and self-documenting.
