文章目录

TypeScript 工具类型:Record、Omit、Exclude

发布于 2026-04-05 08:51:50 · 浏览 22 次 · 评论 0 条

TypeScript 工具类型:Record、Omit、Exclude

TypeScript 的工具类型是一组内置的泛型类型,能够对已有类型进行转换和组合。掌握这些工具类型,可以让你用更少的代码写出类型安全、可维护性更高的代码。本文将深入讲解三个最常用的工具类型:RecordOmitExclude


什么是工具类型

工具类型本质上是泛型类型的特殊用法,它们接收一个或多个类型作为参数,经过处理后返回一个新的类型。你可以理解为类型层面的「函数」,输入是旧类型,输出是新类型。

TypeScript 提供了很多开箱即用的工具类型,全部定义在 tslib 或内置的类型声明文件中。学会这些工具类型后,你会发现很多重复的类型定义代码都可以被简化。


Record:快速定义对象类型结构

Record<K, V> 是最基础的工具类型之一,它用于创建一个对象类型,其中所有键 K 的类型都映射到值 V 的类型。

基本语法

type Record<K extends keyof any, V> = {
  [P in K]: V;
};

K 是键的类型集合,V 是所有键对应的值的类型。

实际应用

假设你需要定义一个配置对象,键是字符串,值也是字符串:

// 传统写法
interface Config {
  apiUrl: string;
  timeout: string;
  retryCount: string;
}

// 使用 Record
type Config = Record<'apiUrl' | 'timeout' | 'retryCount', string>;

当需要动态生成枚举类型的反向映射时,Record 特别有用:

enum Status {
  PENDING = 'pending',
  APPROVED = 'approved',
  REJECTED = 'reject',
}

// 生成反向映射对象
const statusMap: Record<Status, Status> = {
  [Status.PENDING]: Status.PENDING,
  [Status.APPROVED]: Status.APPROVED,
  [Status.REJECTED]: Status.REJECTED,
};

进阶用法

Record 配合 keyof 可以创建灵活的字典类型:

type UserMap = Record<string, User>;
const users: UserMap = {
  'user-1': { id: 1, name: 'Alice' },
  'user-2': { id: 2, name: 'Bob' },
};

Exclude:精确排除不需要的类型

Exclude<T, U> 用于从类型 T 中排除可以赋值给 U 的类型。它的核心逻辑是「保留 T 中不属于 U 的部分」。

基本语法

type Exclude<T, U> = T extends U ? never : T;

这里用到了条件类型的分布式特性:当 T 是联合类型时,Exclude 会逐个检查每个成员。

实际应用

排除特定的字符串字面量:

type EventType = 'click' | 'doubleClick' | 'hover' | 'keydown';

// 排除 click,只保留其他类型
type NonClickEvent = Exclude<EventType, 'click'>;
// 结果: 'doubleClick' | 'hover' | 'keydown'

在 API 错误处理中很有用:

type ApiResponse<T> = 
  | { status: 200; data: T }
  | { status: 400; error: string }
  | { status: 500; error: string };

// 提取成功响应类型,排除错误响应
type SuccessResponse<T> = Exclude<ApiResponse<T>, { status: 400 | 500; error: string }>;

常见场景

从对象属性类型中排除 nullundefined

type JsonValue = string | number | boolean | null | undefined;

// 处理前的 JSON 值可能包含 null/undefined
type NonNullableJson = Exclude<JsonValue, null | undefined>;
// 结果: string | number | boolean

Omit:删除指定的属性

Omit<T, K> 用于从对象类型 T 中删除一组属性 K,返回剩余属性组成的新类型。与 Pick 相对,Pick 是选取,Omit 是排除。

基本语法

type Omit<T, K extends keyof any> = {
  [P in Exclude<keyof T, K>]: T[P];
};

Omit 内部实际上使用了 Exclude 来过滤键名,然后通过映射类型生成新的类型。

实际应用

从接口中排除敏感信息:

interface User {
  id: number;
  username: string;
  password: string;
  email: string;
  createdAt: Date;
}

// 公开信息不包含 password 和 createdAt
type PublicUser = Omit<User, 'password' | 'createdAt'>;

修改第三方库的类型定义时非常实用:

import React from 'react';

// 排除原生事件中不需要的属性
type CustomInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>;

组合多个属性

可以一次性排除多个键:

interface FormData {
  name: string;
  email: string;
  phone: string;
  address: string;
  cardNumber: string;
  cvv: string;
}

// 移除所有支付相关信息
type SafeFormData = Omit<FormData, 'cardNumber' | 'cvv'>;

三者组合使用

这三个工具类型可以相互配合,解决复杂的类型问题。

场景:过滤 API 响应

interface ApiResponse {
  id: string;
  name: string;
  password: string;
  token: string;
  createdAt: string;
  updatedAt: string;
}

// 只保留可公开展示的字段,同时确保值的类型符合预期
type PublicData = Omit<ApiResponse, 'password' | 'token'>;
type PublicDataMap = Record<keyof PublicData, string | number>;

场景:状态机类型定义

type State = 'idle' | 'loading' | 'success' | 'error' | 'cancelled';

// 排除最终状态,保留可继续流转的状态
type ActiveState = Exclude<State, 'success' | 'error' | 'cancelled'>;

// 创建状态描述映射
const stateDescriptions: Record<State, string> = {
  idle: '等待操作',
  loading: '加载中',
  success: '操作成功',
  error: '发生错误',
  cancelled: '已取消',
};

性能与类型推断

使用工具类型时,TypeScript 会在编译阶段进行类型计算。对于简单的工具类型,TypeScript 的处理非常快速;但如果类型嵌套过深,可能会增加编译时间。

实际开发中建议遵循以下原则:优先使用内置工具类型而非手写复杂类型;避免在泛型参数中嵌套过多类型操作;类型别名命名要清晰,便于调试。

工具类型是 TypeScript 类型系统的精髓所在。Record 帮你快速构建对象结构,Exclude 让你精确控制类型边界,Omit 使修改接口变得简单安全。理解并熟练运用这些工具类型,能够显著提升代码的类型安全性和可维护性。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文