TypeScript 类型系统全景
TypeScript 的类型系统是结构化类型(Structural Typing),不是名义类型。理解这一点是掌握 TS 的关键。
基础类型
ts
// 原始类型
let name: string = 'Alice'
let age: number = 30
let active: boolean = true
let nothing: null = null
let undef: undefined = undefined
let big: bigint = 9007199254740991n
let sym: symbol = Symbol('id')
// 数组
let nums: number[] = [1, 2, 3]
let strs: Array<string> = ['a', 'b']
// 元组(固定长度和类型)
let point: [number, number] = [10, 20]
let entry: [string, number] = ['age', 30]
// any / unknown / never / void
let anything: any = 'hello' // 关闭类型检查,尽量避免
let safe: unknown = getData() // 使用前必须类型收窄
let fn: () => void // 函数无返回值
function fail(): never { // 永远不会正常返回
throw new Error('fatal')
}接口 vs 类型别名
ts
// interface:可扩展,适合定义对象形状
interface User {
id: number
name: string
email?: string // 可选属性
readonly createdAt: Date // 只读
}
// 接口扩展
interface Admin extends User {
role: 'admin' | 'superadmin'
permissions: string[]
}
// 接口合并(Declaration Merging)
interface Window {
myCustomProp: string // 扩展全局 Window 类型
}
// type alias:更灵活,支持联合、交叉、映射等
type ID = string | number
type Point = { x: number; y: number }
type Nullable<T> = T | null
// 交叉类型(合并多个类型)
type AdminUser = User & { role: string }
// interface vs type 选择:
// - 对象形状 → interface(支持合并,更语义化)
// - 联合/交叉/映射类型 → type联合类型与类型收窄
ts
type StringOrNumber = string | number
function format(value: StringOrNumber): string {
// typeof 收窄
if (typeof value === 'string') {
return value.toUpperCase() // 这里 value 是 string
}
return value.toFixed(2) // 这里 value 是 number
}
// 判别联合(Discriminated Union)— 最常用的模式
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rectangle'; width: number; height: number }
| { kind: 'triangle'; base: number; height: number }
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2
case 'rectangle':
return shape.width * shape.height
case 'triangle':
return 0.5 * shape.base * shape.height
default:
// 穷举检查:如果新增了 kind 但没处理,这里会报错
const _exhaustive: never = shape
throw new Error(`未处理的形状: ${_exhaustive}`)
}
}
// in 操作符收窄
type Cat = { meow(): void }
type Dog = { bark(): void }
function makeSound(animal: Cat | Dog) {
if ('meow' in animal) {
animal.meow() // Cat
} else {
animal.bark() // Dog
}
}
// 自定义类型守卫
function isUser(obj: unknown): obj is User {
return typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj
}泛型基础
ts
// 泛型函数
function identity<T>(value: T): T {
return value
}
// 泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const user = { id: 1, name: 'Alice' }
getProperty(user, 'name') // string
getProperty(user, 'id') // number
// getProperty(user, 'age') // ❌ 编译错误
// 泛型接口
interface Repository<T> {
findById(id: number): Promise<T>
findAll(): Promise<T[]>
save(entity: T): Promise<T>
delete(id: number): Promise<void>
}
// 泛型类
class Stack<T> {
private items: T[] = []
push(item: T): void { this.items.push(item) }
pop(): T | undefined { return this.items.pop() }
peek(): T | undefined { return this.items[this.items.length - 1] }
get size(): number { return this.items.length }
}
const stack = new Stack<number>()
stack.push(1)
stack.push(2)
stack.pop() // 2工具类型
ts
interface User {
id: number
name: string
email: string
password: string
createdAt: Date
}
// Partial<T>:所有属性变可选
type UserUpdate = Partial<User>
// Required<T>:所有属性变必填
type RequiredUser = Required<Partial<User>>
// Pick<T, K>:选取部分属性
type UserPreview = Pick<User, 'id' | 'name'>
// Omit<T, K>:排除部分属性
type PublicUser = Omit<User, 'password'>
// Record<K, V>:键值映射
type UserMap = Record<string, User>
type StatusMap = Record<'active' | 'inactive' | 'banned', number>
// Readonly<T>:所有属性只读
type ImmutableUser = Readonly<User>
// ReturnType<T>:获取函数返回类型
function fetchUser(): Promise<User> { /* ... */ }
type FetchResult = ReturnType<typeof fetchUser> // Promise<User>
// Parameters<T>:获取函数参数类型
type FetchParams = Parameters<typeof fetchUser> // []
// NonNullable<T>:排除 null 和 undefined
type SafeString = NonNullable<string | null | undefined> // string
// Awaited<T>:解包 Promise(ES2022)
type UserData = Awaited<Promise<User>> // User模板字面量类型
ts
type EventName = 'click' | 'focus' | 'blur'
type Handler = `on${Capitalize<EventName>}`
// 'onClick' | 'onFocus' | 'onBlur'
// 实际应用:类型安全的事件系统
type CSSProperty = 'margin' | 'padding' | 'border'
type CSSDirection = 'Top' | 'Right' | 'Bottom' | 'Left'
type CSSLonghand = `${CSSProperty}${CSSDirection}`
// 'marginTop' | 'marginRight' | ... | 'borderLeft'
// API 路径类型
type ApiVersion = 'v1' | 'v2'
type Resource = 'users' | 'posts' | 'comments'
type ApiPath = `/api/${ApiVersion}/${Resource}`
// '/api/v1/users' | '/api/v1/posts' | ...satisfies 操作符(TS 4.9)
ts
type Colors = 'red' | 'green' | 'blue'
type ColorMap = Record<Colors, string | [number, number, number]>
// satisfies:验证类型但保留字面量类型推断
const palette = {
red: [255, 0, 0],
green: '#00ff00',
blue: [0, 0, 255]
} satisfies ColorMap
// palette.red 的类型是 [number, number, number](而非 string | [number, number, number])
palette.red.map(v => v * 2) // ✓ 不报错
palette.green.toUpperCase() // ✓ 不报错总结
- TS 是结构化类型系统,形状匹配即可赋值
- 优先用判别联合(Discriminated Union)处理多态
- 工具类型(Partial/Pick/Omit/Record)是日常开发必备
unknown比any更安全,使用前必须收窄satisfies在需要类型验证同时保留推断时非常有用