Advanced TypeScript Patterns for Better Code
Discover powerful TypeScript patterns that will make your code more type-safe, maintainable, and expressive.
Why TypeScript Matters
TypeScript has become the de facto standard for large-scale JavaScript applications. But are you using it to its full potential?
In this article, I will share some advanced patterns that have significantly improved my code quality.
Pattern 1: Discriminated Unions
One of the most powerful features in TypeScript is discriminated unions. They allow you to model complex state machines with full type safety:
type Result =
| { status: 'success'; data: T }
| { status: 'error'; error: Error }
| { status: 'loading' }
Pattern 2: Template Literal Types
Template literal types let you create precise string types:
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type Endpoint = /api/${string}
type Route = ${HTTPMethod} ${Endpoint}
Pattern 3: Branded Types
When you need to distinguish between types that share the same underlying structure:
type UserId = string & { readonly brand: unique symbol }
type OrderId = string & { readonly brand: unique symbol }
This prevents accidentally passing a UserId where an OrderId is expected, even though both are strings.
Pattern 4: Type Guards with Assertions
Create reusable type guards that narrow types effectively:
function assertNonNull(
value: T,
message?: string
): asserts value is NonNullable {
if (value === null || value === undefined) {
throw new Error(message ?? 'Value is null or undefined')
}
}
Conclusion
TypeScript is more than just adding types to JavaScript. When used effectively, it becomes a powerful tool for modeling your domain and catching bugs at compile time.
Invest time in learning these patterns - your future self will thank you.