# Advanced TypeScript Patterns
TypeScript has evolved into a powerful type system that goes far beyond basic type annotations. In this deep dive, we'll explore advanced patterns that can help you write more robust and maintainable code.
## Conditional Types
Conditional types allow you to create types that depend on a condition:
```typescript
type ApiResponse
? { message: T }
: { data: T }
// Usage
type StringResponse = ApiResponse
type NumberResponse = ApiResponse
```
### Practical Example: Safe Array Access
```typescript
type SafeGet
interface User {
id: number
name: string
email: string
}
type UserName = SafeGet
type Invalid = SafeGet
```
## Mapped Types
Mapped types let you create new types by transforming properties of existing types:
```typescript
type Partial
[P in keyof T]?: T[P]
}
type Required
[P in keyof T]-?: T[P]
}
type Readonly
readonly [P in keyof T]: T[P]
}
```
### Custom Mapped Types
```typescript
type Stringify
[K in keyof T]: string
}
type Promisify
[K in keyof T]: Promise
}
interface User {
id: number
name: string
active: boolean
}
type StringUser = Stringify
// { id: string; name: string; active: string }
type AsyncUser = Promisify
// { id: Promise
```
## Template Literal Types
Template literal types enable powerful string manipulation at the type level:
```typescript
type EventName
type ClickEvent = EventName<'click'> // 'onClick'
type HoverEvent = EventName<'hover'> // 'onHover'
```
### Building a Type-Safe Event System
```typescript
type EventMap = {
click: { x: number; y: number }
hover: { element: HTMLElement }
scroll: { top: number; left: number }
}
type EventHandler
event: EventMap[T]
) => void
type EventHandlers = {
[K in keyof EventMap as `on${Capitalize
}
// Result:
// {
// onClick?: (event: { x: number; y: number }) => void
// onHover?: (event: { element: HTMLElement }) => void
// onScroll?: (event: { top: number; left: number }) => void
// }
```
## Utility Types in Action
### Deep Readonly
```typescript
type DeepReadonly
readonly [P in keyof T]: T[P] extends object
? DeepReadonly
: T[P]
}
interface Config {
database: {
host: string
port: number
credentials: {
username: string
password: string
}
}
}
type ReadonlyConfig = DeepReadonly
// All properties and nested properties are readonly
```
### Type-Safe Object Paths
```typescript
type Paths
? {
[K in keyof T]: K extends string
? T[K] extends object
? K | `${K}.${Paths
: K
: never
}[keyof T]
: never
type UserPaths = Paths
// 'id' | 'name' | 'email' | 'profile' | 'profile.bio' | 'profile.avatar'
```
## Advanced Function Types
### Function Overloads with Conditional Types
```typescript
interface Database {
get
get
get
}
// Or using conditional types:
type GetReturnType
T extends 'user' ? User :
T extends 'post' ? Post :
T extends 'comment' ? Comment :
never
interface Database {
get
type: T,
id: string
): Promise
}
```
## Best Practices
1. **Start Simple**: Don't over-engineer types from the beginning
2. **Use Type Guards**: Combine runtime checks with type narrowing
3. **Leverage Utility Types**: Use built-in utilities before creating custom ones
4. **Document Complex Types**: Add comments for complex type logic
5. **Test Your Types**: Use type-level tests to ensure correctness
## Conclusion
Advanced TypeScript patterns unlock powerful capabilities for creating type-safe, maintainable applications. While these patterns might seem complex at first, they become invaluable tools for building robust software systems.
The key is to gradually incorporate these patterns into your codebase, starting with simpler use cases and building up to more complex scenarios as your understanding grows.
---
*Have you used any of these advanced TypeScript patterns in your projects? Share your experiences in the comments!*