TypeScript 高级类型技巧:提升代码质量
TypeScript 高级类型技巧:提升代码质量
TypeScript 的类型系统非常强大,掌握高级类型技巧可以让你的代码更加安全、可维护。本文将介绍一些实用的高级类型特性。
1. 泛型(Generics)
泛型是 TypeScript 中最强大的特性之一,它允许我们编写可重用的代码。
基础泛型
// 简单的泛型函数
function identity<T>(arg: T): T {
return arg
}
// 使用
const result1 = identity<string>("hello") // 类型: string
const result2 = identity(42) // 类型推断: number
泛型约束
// 约束泛型必须有 length 属性
interface Lengthwise {
length: number
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
logLength("hello") // ✅ 字符串有 length
logLength([1, 2, 3]) // ✅ 数组有 length
logLength({ length: 10, value: 3 }) // ✅ 对象有 length
// logLength(42) // ❌ 数字没有 length
泛型接口
// API 响应的通用接口
interface ApiResponse<T> {
data: T
status: number
message: string
}
// 用户数据
interface User {
id: number
name: string
email: string
}
// 使用
async function fetchUser(id: number): Promise<ApiResponse<User>> {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
// 文章列表
interface Post {
id: number
title: string
content: string
}
async function fetchPosts(): Promise<ApiResponse<Post[]>> {
const response = await fetch('/api/posts')
return response.json()
}
2. 条件类型(Conditional Types)
条件类型允许我们根据条件选择类型,类似于三元运算符。
基础条件类型
// T extends U ? X : Y
type IsString<T> = T extends string ? true : false
type A = IsString<string> // true
type B = IsString<number> // false
实用示例:提取函数返回类型
// 如果 T 是函数,提取返回类型;否则返回 never
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never
function getUser() {
return { id: 1, name: "张三" }
}
type UserType = ReturnTypeOf<typeof getUser>
// 类型: { id: number; name: string }
分布式条件类型
// 从联合类型中排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T
type A = NonNullable<string | null | undefined> // string
type B = NonNullable<number | null> // number
3. 映射类型(Mapped Types)
映射类型允许我们基于旧类型创建新类型。
Partial - 所有属性变为可选
interface User {
id: number
name: string
email: string
}
// 内置的 Partial 实现
type MyPartial<T> = {
[P in keyof T]?: T[P]
}
type PartialUser = Partial<User>
// 等同于:
// {
// id?: number
// name?: string
// email?: string
// }
// 实际应用:更新用户信息
function updateUser(id: number, updates: Partial<User>) {
// 只需要传递要更新的字段
}
updateUser(1, { name: "李四" }) // ✅
updateUser(2, { email: "test@example.com" }) // ✅
Required - 所有属性变为必需
interface Config {
host?: string
port?: number
timeout?: number
}
type RequiredConfig = Required<Config>
// 等同于:
// {
// host: string
// port: number
// timeout: number
// }
Readonly - 所有属性变为只读
interface User {
id: number
name: string
}
type ReadonlyUser = Readonly<User>
// 等同于:
// {
// readonly id: number
// readonly name: string
// }
const user: ReadonlyUser = { id: 1, name: "张三" }
// user.name = "李四" // ❌ 错误:无法分配到只读属性
Pick - 选择部分属性
interface User {
id: number
name: string
email: string
password: string
createdAt: Date
}
// 只选择公开的用户信息
type PublicUser = Pick<User, 'id' | 'name' | 'email'>
// 等同于:
// {
// id: number
// name: string
// email: string
// }
Omit - 排除部分属性
// 排除敏感信息
type SafeUser = Omit<User, 'password'>
// 等同于:
// {
// id: number
// name: string
// email: string
// createdAt: Date
// }
4. 实用工具类型
Record - 创建对象类型
// Record<Keys, Type>
type PageInfo = {
title: string
url: string
}
type Pages = 'home' | 'about' | 'contact'
const pages: Record<Pages, PageInfo> = {
home: { title: '首页', url: '/' },
about: { title: '关于', url: '/about' },
contact: { title: '联系', url: '/contact' },
}
Extract - 提取联合类型的子集
type T1 = Extract<'a' | 'b' | 'c', 'a' | 'f'> // 'a'
type T2 = Extract<string | number | (() => void), Function> // () => void
Exclude - 排除联合类型的子集
type T1 = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // 'c'
type T2 = Exclude<string | number | boolean, boolean> // string | number
5. 高级实战案例
案例 1:类型安全的事件系统
// 定义事件映射
interface EventMap {
'user:login': { userId: number; timestamp: Date }
'user:logout': { userId: number }
'post:create': { postId: number; title: string }
'post:delete': { postId: number }
}
// 类型安全的事件发射器
class TypedEventEmitter {
private listeners: {
[K in keyof EventMap]?: Array<(data: EventMap[K]) => void>
} = {}
// 监听事件
on<K extends keyof EventMap>(
event: K,
callback: (data: EventMap[K]) => void
) {
if (!this.listeners[event]) {
this.listeners[event] = []
}
this.listeners[event]!.push(callback)
}
// 触发事件
emit<K extends keyof EventMap>(event: K, data: EventMap[K]) {
const callbacks = this.listeners[event]
if (callbacks) {
callbacks.forEach(callback => callback(data))
}
}
}
// 使用
const emitter = new TypedEventEmitter()
// ✅ 类型正确
emitter.on('user:login', (data) => {
console.log(`用户 ${data.userId} 登录`)
})
// ✅ 类型正确
emitter.emit('user:login', {
userId: 1,
timestamp: new Date()
})
// ❌ 类型错误:缺少 timestamp
// emitter.emit('user:login', { userId: 1 })
案例 2:深度只读类型
// 递归地将所有属性变为只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P]
}
interface Config {
database: {
host: string
port: number
credentials: {
username: string
password: string
}
}
cache: {
enabled: boolean
ttl: number
}
}
type ReadonlyConfig = DeepReadonly<Config>
const config: ReadonlyConfig = {
database: {
host: 'localhost',
port: 5432,
credentials: {
username: 'admin',
password: 'secret'
}
},
cache: {
enabled: true,
ttl: 3600
}
}
// ❌ 所有层级都是只读的
// config.database.host = 'newhost'
// config.database.credentials.password = 'newpass'
案例 3:类型安全的 API 客户端
// API 端点定义
interface ApiEndpoints {
'/users': {
GET: { response: User[] }
POST: { body: Omit<User, 'id'>; response: User }
}
'/users/:id': {
GET: { params: { id: number }; response: User }
PUT: { params: { id: number }; body: Partial<User>; response: User }
DELETE: { params: { id: number }; response: void }
}
'/posts': {
GET: { query: { page?: number; limit?: number }; response: Post[] }
POST: { body: Omit<Post, 'id'>; response: Post }
}
}
// 类型安全的 API 客户端
class ApiClient {
async request<
Path extends keyof ApiEndpoints,
Method extends keyof ApiEndpoints[Path]
>(
path: Path,
method: Method,
options?: ApiEndpoints[Path][Method] extends { body: infer B }
? { body: B }
: ApiEndpoints[Path][Method] extends { params: infer P }
? { params: P }
: ApiEndpoints[Path][Method] extends { query: infer Q }
? { query: Q }
: never
): Promise<
ApiEndpoints[Path][Method] extends { response: infer R } ? R : never
> {
// 实现细节...
return {} as any
}
}
// 使用
const api = new ApiClient()
// ✅ 类型安全
const users = await api.request('/users', 'GET')
// users 类型: User[]
// ✅ 类型安全
const newUser = await api.request('/users', 'POST', {
body: { name: '张三', email: 'zhang@example.com' }
})
// newUser 类型: User
// ❌ 类型错误:缺少必需的 body
// await api.request('/users', 'POST')
6. 最佳实践
1. 优先使用类型推断
// ❌ 不必要的类型注解
const name: string = "张三"
const age: number = 25
// ✅ 让 TypeScript 推断
const name = "张三" // 推断为 string
const age = 25 // 推断为 number
2. 使用 const 断言
// ❌ 类型过于宽泛
const config = {
host: 'localhost',
port: 3000
}
// config 类型: { host: string; port: number }
// ✅ 使用 const 断言
const config = {
host: 'localhost',
port: 3000
} as const
// config 类型: { readonly host: "localhost"; readonly port: 3000 }
3. 避免使用 any
// ❌ 失去类型安全
function processData(data: any) {
return data.value
}
// ✅ 使用泛型或 unknown
function processData<T>(data: T) {
return data
}
// 或者
function processData(data: unknown) {
if (typeof data === 'object' && data !== null && 'value' in data) {
return (data as { value: any }).value
}
}
4. 使用严格模式
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true
}
}
总结
TypeScript 的高级类型系统为我们提供了强大的工具来编写类型安全的代码。关键要点:
- 善用泛型,编写可重用的代码
- 掌握条件类型,实现复杂的类型逻辑
- 活用映射类型,转换现有类型
- 使用工具类型,简化常见操作
- 遵循最佳实践,保持代码质量
通过这些技巧,你将能够构建更加健壮、可维护的 TypeScript 应用。
相关资源
标签: #TypeScript #类型系统 #泛型 #类型安全 #最佳实践
发布日期: 2025-02-08
作者: 君知博客团队
Comments
Share your thoughts and join the discussion
Comments (0)
Related Articles
TypeScript Advanced Type System: Mastering Generics and Type Gymnastics
Deep dive into TypeScript advanced types including generics, conditional types, mapped types, template literals, and type gymnastics. Learn practical techniques for building type-safe applications with real-world examples and best practices.
Docker Containerization Best Practices: Complete Guide to Production-Ready Containers
Master Docker containerization with multi-stage builds, security hardening, Docker Compose orchestration, and production deployment strategies. Learn how to build efficient, secure, and scalable containerized applications.
PostgreSQL Performance Optimization: Complete Guide to Database Tuning
Master PostgreSQL performance optimization with indexing strategies, query tuning, EXPLAIN analysis, VACUUM operations, connection pooling, and partitioning. Learn practical techniques to scale your database for high-traffic applications.
Please or to comment