正在加载,请稍候…

TypeScript 实用类型:Partial、Pick、Omit、Record 等详解

TypeScript 内置实用类型(Partial、Required、Pick、Omit、Record、Exclude、Extract、ReturnType 等

TypeScript Utility Types: Partial, Pick, Omit, Record, and More

TypeScript 实用类型:实战参考

TypeScript 自带一套内置的实用类型,用于转换现有类型。这些类型让你能从已有类型派生出新类型,无需重复定义类型,从而减少维护负担并保持代码库 DRY。

TypeScript Utility Types: Partial, Pick, Omit, Record, and More illustration

对象转换类型

Partial<T>

将所有属性变为可选。

interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

// 所有字段可选——适用于更新负载
 type UserUpdate = Partial<User>;

function updateUser(id: number, changes: Partial<User>) {
  // changes 可以包含 User 字段的任意子集
}

updateUser(1, { name: 'Alice' });           // ✅
updateUser(1, { email: 'a@b.com', role: 'admin' });  // ✅

Required<T>

将所有属性变为必填(与 Partial 相反)。

interface Config {
  timeout?: number;
  retries?: number;
  baseUrl?: string;
}

// 初始化后所有字段必填
 type ResolvedConfig = Required<Config>;

function resolveConfig(input: Config): ResolvedConfig {
  return {
    timeout: input.timeout ?? 5000,
    retries: input.retries ?? 3,
    baseUrl: input.baseUrl ?? 'https://api.example.com',
  };
}

Readonly<T>

将所有属性变为只读(不可重新赋值)。

const config: Readonly<Config> = {
  timeout: 5000,
  retries: 3,
  baseUrl: 'https://api.example.com',
};

config.timeout = 1000;  // ❌ 错误:无法分配到 'timeout'(只读)

Pick<T, K>

创建一个仅包含选定键的类型。

interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
}

// 面向公众的用户——排除敏感字段
 type PublicUser = Pick<User, 'id' | 'name' | 'email'>;

// 类型:{ id: number; name: string; email: string }

function getPublicProfile(user: User): PublicUser {
  return { id: user.id, name: user.name, email: user.email };
}

Omit<T, K>

创建一个移除了指定键的类型。

// 移除敏感和自动生成字段,用于创建输入
 type CreateUserInput = Omit<User, 'id' | 'passwordHash' | 'createdAt'>;

// 类型:{ name: string; email: string }

function createUser(input: CreateUserInput): User {
  return {
    ...input,
    id: generateId(),
    passwordHash: hashPassword(input.email),
    createdAt: new Date(),
  };
}

Pick vs Omit: 当你需要大型类型的一小部分时使用 Pick;当你需要类型的大部分字段但排除少数几个时使用 Omit。

TypeScript Utility Types: Partial, Pick, Omit, Record, and More illustration

Record<K, V>

创建一个对象类型,键为 K 类型,值为 V 类型。

// 从字符串键到数字的映射
 type ScoreMap = Record<string, number>;
const scores: ScoreMap = { alice: 95, bob: 87 };

// 将枚举值映射到配置对象
 type EnvironmentConfig = Record<'dev' | 'staging' | 'prod', {
  apiUrl: string;
  debug: boolean;
}>;

const envConfig: EnvironmentConfig = {
  dev:     { apiUrl: 'http://localhost:3000', debug: true },
  staging: { apiUrl: 'https://staging.api.example.com', debug: true },
  prod:    { apiUrl: 'https://api.example.com', debug: false },
};

// 更严格的约束:键必须是有效的 HTTP 方法
 type HttpMethodHandlers = Record<'GET' | 'POST' | 'PUT' | 'DELETE', Function>;

联合/交叉类型辅助

Exclude<T, U>

从联合类型 T 中移除可赋值给 U 的类型。

type Status = 'pending' | 'active' | 'deleted' | 'banned';

// 移除管理状态
 type UserFacingStatus = Exclude<Status, 'deleted' | 'banned'>;
// 类型:'pending' | 'active'

type NonNullableString = Exclude<string | null | undefined, null | undefined>;
// 类型:string

Extract<T, U>

仅保留联合类型 T 中可赋值给 U 的类型(与 Exclude 相反)。

type Events = 'click' | 'focus' | 'blur' | 'keydown' | 'keyup';

// 仅键盘事件
 type KeyboardEvents = Extract<Events, 'keydown' | 'keyup' | 'keypress'>;
// 类型:'keydown' | 'keyup'

// 从联合类型中提取对象类型
 type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number } | string;
type ShapeObject = Extract<Shape, object>;
// 类型:{ kind: 'circle'; radius: number } | { kind: 'square'; side: number }

NonNullable<T>

从类型中移除 nullundefined

type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// 类型:string

function processName(name: string | null): string {
  const safe: NonNullable<typeof name> = name ?? 'Anonymous';
  return safe.toUpperCase();
}

函数相关类型

TypeScript Utility Types: Partial, Pick, Omit, Record, and More illustration

ReturnType<T>

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

function fetchUser(id: number) {
  return { id, name: 'Alice', email: 'alice@example.com' };
}

type FetchedUser = ReturnType<typeof fetchUser>;
// 类型:{ id: number; name: string; email: string }

// 也适用于异步函数
 async function getConfig() {
  return { timeout: 5000, debug: false };
}

type Config = Awaited<ReturnType<typeof getConfig>>;
// 类型:{ timeout: number; debug: boolean }
// 注意:Awaited 会展开 Promise

Parameters<T>

将函数参数提取为元组类型。

function createEvent(name: string, date: Date, attendees: number) {
  // ...
}

type CreateEventParams = Parameters<typeof createEvent>;
// 类型:[name: string, date: Date, attendees: number]

// 对包装函数很有用
 function createEventWithLogging(...args: Parameters<typeof createEvent>) {
  console.log('Creating event:', args[0]);
  return createEvent(...args);
}

ConstructorParameters<T>

提取构造函数参数。

class HttpClient {
  constructor(baseUrl: string, timeout: number, headers: Record<string, string>) {}
}

type ClientConfig = ConstructorParameters<typeof HttpClient>;
// 类型:[baseUrl: string, timeout: number, headers: Record<string, string>]

InstanceType<T>

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

class ApiClient {
  get(url: string) { return fetch(url); }
  post(url: string, body: unknown) { return fetch(url, { method: 'POST' }); }
}

type Client = InstanceType<typeof ApiClient>;
// 类型:ApiClient

// 对工厂模式很有用
 function createClient(): InstanceType<typeof ApiClient> {
  return new ApiClient();
}

组合实用类型

实际类型通常组合多个实用类型:

interface Article {
  id: string;
  title: string;
  content: string;
  authorId: string;
  publishedAt: Date;
  updatedAt: Date;
  tags: string[];
}

// 创建输入:无自动生成字段
 type CreateArticleInput = Omit<Article, 'id' | 'publishedAt' | 'updatedAt'>;

// 更新输入:除 id 外所有字段可选
 type UpdateArticleInput = Partial<Omit<Article, 'id'>> & Pick<Article, 'id'>;

// 文章预览:仅显示字段
 type ArticlePreview = Pick<Article, 'id' | 'title' | 'authorId' | 'publishedAt' | 'tags'>;

// 深度 Partial(实用类型默认不深度处理)
 type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

模板字面量类型(高级)

// 从事件名称生成事件处理函数名称
 type EventNames = 'click' | 'focus' | 'blur';
type HandlerNames = `on${Capitalize<EventNames>}`;
// 类型:'onClick' | 'onFocus' | 'onBlur'

// 生成 getter/setter 对
 type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

interface User { name: string; age: number; }
type UserGetters = Getters<User>;
// 类型:{ getName: () => string; getAge: () => number }

快速参考

实用类型 作用
Partial<T> 所有属性可选
Required<T> 所有属性必填
Readonly<T> 所有属性只读
Pick<T, K> 仅保留 K 键
Omit<T, K> 移除 K 键
Record<K, V> 键为 K、值为 V 的对象
Exclude<T, U> 从联合类型 T 中移除 U
Extract<T, U> 仅保留联合类型 T 中的 U
NonNullable<T> 移除 null/undefined
ReturnType<T> 函数返回类型
Parameters<T> 函数参数类型
Awaited<T> 展开 Promise 类型

→ 使用 JSON Viewer 查看和探索复杂的 JSON 数据结构。