Appearance
TypeScript 进阶技巧
TypeScript 作为 JavaScript 的超集,提供了强大的类型系统。本文将深入探讨 TypeScript 的高级特性,帮助你写出更加健壮和优雅的代码。
泛型(Generics)
泛型是 TypeScript 最强大的特性之一,它允许我们创建可重用的组件,这些组件可以处理多种类型。
基础泛型
typescript
// 简单的泛型函数
function identity<T>(arg: T): T {
return arg
}
// 使用
const output1 = identity<string>("myString")
const output2 = identity<number>(123)
const output3 = identity("myString") // 类型推断泛型约束
使用 extends 关键字来约束泛型类型:
typescript
interface Lengthwise {
length: number
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
loggingIdentity("hello") // ✅ 字符串有 length 属性
loggingIdentity([1, 2, 3]) // ✅ 数组有 length 属性
loggingIdentity(123) // ❌ 数字没有 length 属性泛型接口和类
typescript
// 泛型接口
interface GenericInterface<T> {
value: T
getValue(): T
}
// 泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
const myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = (x, y) => x + y条件类型(Conditional Types)
条件类型允许我们根据类型关系选择类型:
typescript
type IsArray<T> = T extends Array<any> ? true : false
type Test1 = IsArray<string[]> // true
type Test2 = IsArray<string> // false分布式条件类型
typescript
type ToArray<T> = T extends any ? T[] : never
type StrArrOrNumArr = ToArray<string | number>
// string[] | number[]infer 关键字
infer 用于在条件类型中推断类型:
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any
type T0 = ReturnType<() => string> // string
type T1 = ReturnType<(x: number) => number> // number映射类型(Mapped Types)
映射类型允许我们基于旧类型创建新类型:
typescript
// 将所有属性变为可选
type Partial<T> = {
[P in keyof T]?: T[P]
}
// 将所有属性变为只读
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
// 将所有属性变为必需
type Required<T> = {
[P in keyof T]-?: T[P]
}实际应用
typescript
interface User {
name: string
age: number
email: string
}
// 创建所有属性可选的新类型
type PartialUser = Partial<User>
// { name?: string; age?: number; email?: string }
// 创建只读版本
type ReadonlyUser = Readonly<User>
// { readonly name: string; readonly age: number; readonly email: string }工具类型(Utility Types)
TypeScript 提供了许多内置的工具类型:
Pick 和 Omit
typescript
interface Todo {
title: string
description: string
completed: boolean
}
// Pick: 选择部分属性
type TodoPreview = Pick<Todo, "title" | "completed">
// { title: string; completed: boolean }
// Omit: 排除部分属性
type TodoInfo = Omit<Todo, "completed" | "description">
// { title: string }Record
typescript
// Record<K, T> 创建一个对象类型,其键为 K,值为 T
type PageInfo = {
title: string
}
type Page = "home" | "about" | "contact"
const x: Record<Page, PageInfo> = {
home: { title: "Home" },
about: { title: "About" },
contact: { title: "Contact" }
}Exclude 和 Extract
typescript
type T0 = Exclude<"a" | "b" | "c", "a"> // "b" | "c"
type T1 = Extract<"a" | "b" | "c", "a" | "f"> // "a"模板字面量类型
TypeScript 4.1 引入了模板字面量类型:
typescript
type World = "world"
type Greeting = `hello ${World}` // "hello world"
type EmailLocaleIDs = "welcome_email" | "email_heading"
type FooterLocaleIDs = "footer_title" | "footer_sendoff"
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"类型守卫(Type Guards)
类型守卫帮助我们缩小类型范围:
typescript
// typeof 类型守卫
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value
}
return padding + value
}
// instanceof 类型守卫
class Bird {
fly() {
console.log("flying")
}
}
function move(animal: Bird | Fish) {
if (animal instanceof Bird) {
animal.fly()
}
}
// 自定义类型守卫
function isString(value: unknown): value is string {
return typeof value === "string"
}装饰器(Decorators)
装饰器是一种特殊类型的声明,可以附加到类、方法、属性等:
typescript
function sealed(constructor: Function) {
Object.seal(constructor)
Object.seal(constructor.prototype)
}
@sealed
class BugReport {
type = "report"
title: string
constructor(t: string) {
this.title = t
}
}实际应用场景
API 响应类型
typescript
// 定义 API 响应类型
type ApiResponse<T> = {
success: true
data: T
} | {
success: false
error: string
}
async function fetchUser(id: number): Promise<ApiResponse<User>> {
try {
const user = await api.getUser(id)
return { success: true, data: user }
} catch (error) {
return { success: false, error: error.message }
}
}表单验证
typescript
type ValidationResult<T> = {
[K in keyof T]?: string
}
function validate<T>(data: T, rules: ValidationRules<T>): ValidationResult<T> {
// 验证逻辑
return {}
}最佳实践
- 充分利用类型推断:让 TypeScript 自动推断类型,减少冗余
- 使用联合类型和字面量类型:提高类型精确度
- 合理使用泛型:提高代码复用性
- 利用工具类型:减少重复的类型定义
- 编写类型守卫:提高类型安全性
总结
TypeScript 的高级特性为我们提供了强大的类型系统,帮助我们构建更加健壮的应用程序。通过合理使用泛型、条件类型、映射类型等特性,我们可以写出更加优雅和可维护的代码。掌握这些进阶技巧,将大大提升你的 TypeScript 开发能力。