Skip to content
Published at:

Utility Type 工具类型

TypeScript 提供了多种内置的工具类型(Utility Types),用于简化常见的类型转换操作。

Awaited<Type>

用于获取 Promise 的返回值类型,支持递归解包嵌套的 Promise。

ts
type A = Awaited<Promise<string>>
// type A = string

type B = Awaited<Promise<Promise<number>>>
// type B = number

type C = Awaited<boolean | Promise<number>>
// type C = number | boolean

常见应用: 在 async 函数中获取返回值的类型定义,或者从第三方库的异步 API 中提取实际返回的数据类型。

ts
async function fetchUser(): Promise<{ name: string; age: number }> {
  return { name: 'Alice', age: 30 }
}

type User = Awaited<ReturnType<typeof fetchUser>>
// type User = { name: string; age: number }

Partial<Type>

将类型 Type 中的所有属性变为可选的(?)。

ts
interface User {
  name: string
  age: number
  email: string
}

type PartialUser = Partial<User>
// type PartialUser = {
//   name?: string
//   age?: number
//   email?: string
// }

const update: PartialUser = { name: 'Bob' } // 只更新部分字段

常见应用: 更新操作中只传入需要修改的字段;配置对象的类型定义,允许用户只提供部分配置项。

ts
function updateUser(id: number, fields: Partial<User>) {
  // 只需要传入要更新的字段
}

updateUser(1, { email: 'new@example.com' })

Required<Type>

将类型 Type 中的所有属性变为必选的,与 Partial 相反。

ts
interface Config {
  host?: string
  port?: number
  ssl?: boolean
}

type RequiredConfig = Required<Config>
// type RequiredConfig = {
//   host: string
//   port: number
//   ssl: boolean
// }

const config: RequiredConfig = {
  host: 'localhost',
  port: 443,
  ssl: true,
}

常见应用: 当某些配置项在特定场景下必须全部提供时;消除可选属性的不确定性。

ts
// 比如:生产环境必须提供所有配置
function createProdConfig(config: Required<Config>) {
  // config.host, config.port, config.ssl 都是必选的
}

Readonly<Type>

将类型 Type 中的所有属性变为只读的。

ts
interface Point {
  x: number
  y: number
}

type ReadonlyPoint = Readonly<Point>
// type ReadonlyPoint = {
//   readonly x: number
//   readonly y: number
// }

const p: ReadonlyPoint = { x: 10, y: 20 }
// p.x = 30 // Error: Cannot assign to 'x' because it is a read-only property.

常见应用: 定义不可变数据;确保函数不会意外修改传入的对象;Redux 中的 state 类型定义。

ts
function printPoint(point: Readonly<Point>) {
  // point.x = 100 // Error,确保函数内部不会修改参数
  console.log(point.x, point.y)
}

// 配合 as const 创建深度只读对象
const config = {
  host: 'localhost',
  port: 8080,
} as const
// config.host = 'other' // Error

Record<Keys, Type>

构造一个对象类型,其键的类型为 Keys,值的类型为 Type

ts
type Roles = 'admin' | 'user' | 'guest'
type RoleConfig = Record<Roles, { permissions: string[] }>

const config: RoleConfig = {
  admin: { permissions: ['read', 'write', 'delete'] },
  user: { permissions: ['read', 'write'] },
  guest: { permissions: ['read'] },
}

常见应用: 构建映射表(如权限映射、状态映射);将联合类型转换为键值对结构;字典/缓存对象的类型定义。

ts
// 状态码映射
type StatusCode = 200 | 404 | 500
type StatusMessage = Record<StatusCode, string>

const messages: StatusMessage = {
  200: 'OK',
  404: 'Not Found',
  500: 'Internal Server Error',
}

// 用 Record 构建字典
type Dict<T> = Record<string, T>
const userMap: Dict<{ name: string }> = {}
userMap['user1'] = { name: 'Alice' }

Pick<Type, Keys>

从类型 Type 中选取一组属性来构造新类型。

ts
interface User {
  id: number
  name: string
  email: string
  password: string
}

type PublicUser = Pick<User, 'id' | 'name'>
// type PublicUser = {
//   id: number
//   name: string
// }

const publicInfo: PublicUser = { id: 1, name: 'Alice' }

常见应用: 从已有类型中提取需要的字段,适合用于 API 返回值的类型定义、DTO 对象的类型定义。

ts
// 用户列表只展示 id 和 name
type UserListItem = Pick<User, 'id' | 'name'>

// 用户表单只需要 email 和 name
type UserForm = Pick<User, 'name' | 'email'>

Omit<Type, Keys>

从类型 Type 中排除一组属性来构造新类型,与 Pick 相反。

ts
interface User {
  id: number
  name: string
  email: string
  password: string
}

type UserWithoutPassword = Omit<User, 'password'>
// type UserWithoutPassword = {
//   id: number
//   name: string
//   email: string
// }

// 可以安全地返回给前端(不含密码)
const safe: UserWithoutPassword = { id: 1, name: 'Alice', email: 'alice@example.com' }

常见应用: 排除敏感字段(如密码)后返回给客户端;排除不需要的字段创建子类型。

ts
// 排除多个字段
type UserSummary = Omit<User, 'password' | 'email'>

// 配合泛型使用
function sanitizeUser<T extends User>(user: T): Omit<T, 'password'> {
  const { password, ...rest } = user
  return rest
}

Exclude<UnionType, ExcludedMembers>

从联合类型中排除某些类型。

ts
type All = 'a' | 'b' | 'c' | 'd'
type WithoutA = Exclude<All, 'a'>
// type WithoutA = 'b' | 'c' | 'd'

type Event = 'click' | 'scroll' | 'mousemove'
type NotScroll = Exclude<Event, 'scroll'>
// type NotScroll = 'click' | 'mousemove'

常见应用: 从联合类型中过滤掉不需要的成员;类型层面的集合减法操作。

ts
// 从一组 HTTP 方法中排除不安全的
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
type SafeMethod = Exclude<HttpMethod, 'POST' | 'PUT' | 'DELETE' | 'PATCH'>
// type SafeMethod = 'GET'

// 排除 null 和 undefined(可以用 NonNullable 更简洁)
type T1 = Exclude<string | number | null | undefined, null | undefined>
// type T1 = string | number

Extract<Type, Union>

从类型 Type 中提取可以赋值给 Union 的类型,与 Exclude 相反。

ts
type All = 'a' | 'b' | 'c' | 'd'
type OnlyAB = Extract<All, 'a' | 'b'>
// type OnlyAB = 'a' | 'b'

type Mixed = string | number | boolean | (() => void)
type Callable = Extract<Mixed, Function>
// type Callable = () => void

常见应用: 从联合类型中提取满足条件的子集;提取函数类型。

ts
// 提取特定的事件类型
type EventName = 'click' | 'scroll' | 'keydown' | 'keyup'
type KeyboardEvents = Extract<EventName, `key${string}`>
// type KeyboardEvents = 'keydown' | 'keyup'

// 从混合类型中提取数组类型
type Types = string[] | number[] | boolean
type Arrays = Extract<Types, unknown[]>
// type Arrays = string[] | number[]

NonNullable<Type>

从类型 Type 中排除 nullundefined

ts
type T1 = NonNullable<string | null | undefined>
// type T1 = string

type T2 = NonNullable<number[] | null>
// type T2 = number[]

type T3 = NonNullable<null | undefined>
// type T3 = never

常见应用: 过滤掉可空类型,确保值的类型安全。

ts
function getValue(): string | null {
  return Math.random() > 0.5 ? 'hello' : null
}

// 使用 filter 配合类型守卫
const values = [getValue(), getValue(), getValue()]
const nonNullValues = values.filter((v): v is NonNullable<typeof v> => v !== null)
// nonNullValues: string[]

// 表单字段的验证后类型
type FormField = string | null | undefined
type ValidField = NonNullable<FormField>
// type ValidField = string

Parameters<Type>

提取函数类型的参数列表,返回一个元组类型。

ts
declare function foo(a: string, b: number): void

type P = Parameters<typeof foo>
// type P = [a: string, b: number]

const args: P = ['hello', 42]
foo(...args)

常见应用: 获取第三方函数的参数类型;编写高阶函数时复用参数类型;在 React 中提取组件 Props。

ts
// 复用现有函数的参数类型
function logEvent(event: string, data: Record<string, unknown>) { /* ... */ }

type LogEventParams = Parameters<typeof logEvent>
// type LogEventParams = [event: string, data: Record<string, unknown>]

// 在高阶函数中使用
function wrapLog(...args: LogEventParams) {
  console.log('[LOG]', args[0])
  logEvent(...args)
}

ConstructorParameters<Type>

提取构造函数类型的参数列表,返回一个元组或数组类型。

ts
class Person {
  constructor(public name: string, public age: number) {}
}

type CP = ConstructorParameters<typeof Person>
// type CP = [name: string, age: number]

const params: CP = ['Alice', 30]
const person = new Person(...params)

常见应用: 在工厂函数或依赖注入中复用构造函数参数类型。

ts
// 抽象工厂模式
abstract class Animal {
  abstract makeSound(): void
}

class Dog extends Animal {
  constructor(public breed: string) { super() }
  makeSound() { console.log('Woof') }
}

class Cat extends Animal {
  constructor(public color: string) { super() }
  makeSound() { console.log('Meow') }
}

type AnimalConstructor<T extends Animal> = new (...args: any[]) => T

function createAnimal<T extends Animal>(
  ctor: AnimalConstructor<T>,
  ...args: ConstructorParameters<AnimalConstructor<T>>
): T {
  return new ctor(...args)
}

const dog = createAnimal(Dog, 'Golden Retriever')

ReturnType<Type>

提取函数类型的返回值类型。

ts
declare function createUser(name: string): { id: number; name: string }

type R = ReturnType<typeof createUser>
// type R = { id: number; name: string }

const user: R = { id: 1, name: 'Alice' }

常见应用: 获取函数返回值类型,避免重复定义;在 Redux 中推导 action 类型。

ts
// 从工厂函数推导返回类型
function createCounter() {
  return {
    count: 0,
    increment() { this.count++ },
    decrement() { this.count-- },
  }
}

type Counter = ReturnType<typeof createCounter>

// 在 async 函数中使用
async function fetchData(): Promise<{ items: string[]; total: number }> {
  return { items: ['a', 'b'], total: 2 }
}
type DataResponse = Awaited<ReturnType<typeof fetchData>>
// type DataResponse = { items: string[]; total: number }

InstanceType<Type>

提取构造函数类型的实例类型。

ts
class Person {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

type P = InstanceType<typeof Person>
// type P = Person

const p: P = new Person('Alice', 30)

常见应用: 在工厂函数或依赖注入容器中获取构造函数创建的实例类型。

ts
// 依赖注入容器
class Container {
  private services = new Map<new (...args: any[]) => any, any>()

  register<T extends new (...args: any[]) => any>(ctor: T, instance: InstanceType<T>) {
    this.services.set(ctor, instance)
  }

  resolve<T extends new (...args: any[]) => any>(ctor: T): InstanceType<T> {
    return this.services.get(ctor)
  }
}

const container = new Container()
container.register(Person, new Person('Alice', 30))
const resolved = container.resolve(Person) // type: Person

NoInfer<Type>

阻止 TypeScript 从泛型参数中进行类型推断,强制使用显式声明的类型。(TypeScript 5.4+)

ts
function createList<T>(items: T[], defaultValue: NoInfer<T>): T[] {
  return items.length > 0 ? items : [defaultValue]
}

// createList([1, 2], 'default')
// Error: 'default' 是 string,不会被推断为 string | number
// 必须使用与 T 一致的类型

createList([1, 2], 0) // OK

常见应用: 当有多个参数属于同一泛型类型,但希望某些参数不参与类型推断时使用。

ts
// 限制 defaultValue 不能影响 items 的类型推断
function fetchItems<T>(
  url: string,
  fallback: NoInfer<T>
): Promise<T> {
  return fetch(url).then(res => res.json()).catch(() => Promise.resolve(fallback))
}

// 类型推断完全由 url/API 决定,fallback 不会扩大类型
declare function apiGetUser(): Promise<{ id: number; name: string }>

ThisParameterType<Type>

提取函数类型中 this 参数的类型。

ts
function getAge(this: { age: number }) {
  return this.age
}

type ThisType = ThisParameterType<typeof getAge>
// type ThisType = { age: number }

常见应用: 在需要提取方法所属对象类型的高级类型编程中使用。

ts
class Component {
  state = { count: 0 }
  render(this: Component) {
    return this.state.count
  }
}

type CompThis = ThisParameterType<typeof Component.prototype.render>
// type CompThis = Component

OmitThisParameter<Type>

从函数类型中移除 this 参数,返回不带 this 类型的函数类型。

ts
function greet(this: { name: string }, greeting: string) {
  return `${greeting}, ${this.name}`
}

type PlainGreet = OmitThisParameter<typeof greet>
// type PlainGreet = (greeting: string) => string

const greetFn: PlainGreet = greet.bind({ name: 'World' })
greetFn('Hello') // 'Hello, World'

常见应用: 将带有 this 类型的方法转换为普通函数类型,方便作为回调传递。

ts
class Handler {
  data = 'important'
  handle(this: Handler, event: string) {
    console.log(event, this.data)
  }
}

// 直接传递方法会导致 this 丢失
// onClick(handler.handle) // Error: 'this' 类型不匹配

// 使用 OmitThisParameter 获取普通函数签名
type HandleFn = OmitThisParameter<typeof Handler.prototype.handle>
// type HandleFn = (event: string) => void

const boundHandle: HandleFn = new Handler().handle.bind(new Handler())

ThisType<Type>

用于标记上下文中的 this 类型,不返回转换后的类型。通常配合对象字面量使用。

ts
type ObjectDescriptor<D, M> = {
  data?: D
  methods?: M & ThisType<D & M> // methods 中的 this 类型是 D & M
}

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
  const data = desc.data || {} as D
  const methods = desc.methods || {} as M
  return { ...data, ...methods } as D & M
}

const obj = makeObject({
  data: { x: 0, y: 0 },
  methods: {
    moveBy(dx: number, dy: number) {
      this.x += dx // this 的类型是 { x: number; y: number } & { moveBy: ... }
      this.y += dy
    },
  },
})

常见应用: Vue Options API 中 methods 里的 this 能够访问 data 中的属性,就是借助了 ThisType

ts
// 模拟 Vue 2.x 的 Options API 类型推导
interface VueOptions<D, M> {
  data(this: void): D
  methods: M & ThisType<D & M>
}

declare function defineComponent<D, M>(options: VueOptions<D, M>): D & M

const vm = defineComponent({
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++ // this 能访问 data 中的 count
    },
  },
})

Intrinsic String Manipulation Types 内置字符串操作类型

TypeScript 4.1 引入了基于模板字面量类型的内置字符串操作类型,这些类型在编译器中直接实现。

Uppercase<StringType>

将字符串字面量类型的每个字符转换为大写。

ts
type Greeting = 'Hello, World'
type ShoutingGreeting = Uppercase<Greeting>
// type ShoutingGreeting = 'HELLO, WORLD'

type Status = 'success' | 'error'
type UpperStatus = Uppercase<Status>
// type UpperStatus = 'SUCCESS' | 'ERROR'

常见应用: 将枚举风格的字符串联合类型转换为大写形式,统一格式。

Lowercase<StringType>

将字符串字面量类型的每个字符转换为小写。

ts
type Greeting = 'Hello, World'
type QuietGreeting = Lowercase<Greeting>
// type QuietGreeting = 'hello, world'

type Method = 'GET' | 'POST' | 'DELETE'
type LowerMethod = Lowercase<Method>
// type LowerMethod = 'get' | 'post' | 'delete'

常见应用: 将 HTTP 方法或其他标识符统一转换为小写。

Capitalize<StringType>

将字符串字面量类型的首字母转换为大写。

ts
type Method = 'get' | 'post' | 'delete'
type CapitalizedMethod = Capitalize<Method>
// type CapitalizedMethod = 'Get' | 'Post' | 'Delete'

type EventName = 'click'
type HandlerName = `on${Capitalize<EventName>}`
// type HandlerName = 'onClick'

常见应用: 动态生成符合命名规范的类型,比如从事件名生成 handler 名。

ts
type Events = 'click' | 'change' | 'submit'
type Handlers = {
  [K in Events as `on${Capitalize<K>}`]: (event: K) => void
}
// type Handlers = {
//   onClick: (event: 'click') => void
//   onChange: (event: 'change') => void
//   onSubmit: (event: 'submit') => void
// }

Uncapitalize<StringType>

将字符串字面量类型的首字母转换为小写。

ts
type Method = 'GET' | 'POST' | 'DELETE'
type UncapitalizedMethod = Uncapitalize<Method>
// type UncapitalizedMethod = 'gET' | 'pOST' | 'dELETE'

// 更实用的场景:将类名转换为实例变量名
type ClassName = 'UserService'
type InstanceName = Uncapitalize<ClassName>
// type InstanceName = 'userService'

常见应用: 从类名或大写开头的标识符生成小写开头的变量名。

ts
type Services = 'UserService' | 'OrderService' | 'PaymentService'
type ServiceInstances = {
  [K in Services as Uncapitalize<K>]: K
}
// type ServiceInstances = {
//   userService: 'UserService'
//   orderService: 'OrderService'
//   paymentService: 'PaymentService'
// }

总结

工具类型用途
Awaited<T>解包 Promise,获取异步返回值类型
Partial<T>所有属性变为可选
Required<T>所有属性变为必选
Readonly<T>所有属性变为只读
Record<K, T>构造键为 K、值为 T 的对象类型
Pick<T, K>从 T 中选取属性 K 构造新类型
Omit<T, K>从 T 中排除属性 K 构造新类型
Exclude<U, E>从联合类型 U 中排除 E
Extract<T, U>从类型 T 中提取可赋值给 U 的部分
NonNullable<T>排除 null 和 undefined
Parameters<T>提取函数参数类型元组
ConstructorParameters<T>提取构造函数参数类型元组
ReturnType<T>提取函数返回值类型
InstanceType<T>提取构造函数实例类型
NoInfer<T>阻止类型推断
ThisParameterType<T>提取函数 this 参数类型
OmitThisParameter<T>移除函数 this 参数类型
ThisType<T>标记上下文中的 this 类型
Uppercase<S>字符串转大写
Lowercase<S>字符串转小写
Capitalize<S>字符串首字母大写
Uncapitalize<S>字符串首字母小写