TypeScript 工具类型

概述

TypeScript 工具类型是提高开发效率和代码质量的强大工具:

  1. 减少重复代码 :避免重复定义相似的类型
  2. 提高类型安全性 :通过类型转换和约束,减少运行时错误
  3. 增强代码可读性 :更清晰地表达类型意图
  4. 提高开发效率 :快速生成复杂类型,减少手动编写

用法

Partial

将类型 T 的所有属性变为可选

interface User {
  id: number;
  name: string;
  email: string;
}

// 所有属性变为可选
type PartialUser = Partial<User>;
// 等价于:{ id?: number; name?: string; email?: string; }

// 使用示例
const updateUser: PartialUser = { name: "张三" };

Required

将类型 T 的所有属性变为必填

interface Config {
  url?: string;
  timeout?: number;
  headers?: Record<string, string>;
}

// 所有属性变为必填
type RequiredConfig = Required<Config>;
// 等价于:{ url: string; timeout: number; headers: Record<string, string>; }

// 使用示例
const config: RequiredConfig = {
  url: "https://api.example.com",
  timeout: 5000,
  headers: { "Content-Type": "application/json" }
};

Readonly

将类型 T 的所有属性变为只读

interface User {
  id: number;
  name: string;
}

// 所有属性变为只读
type ReadonlyUser = Readonly<User>;
// 等价于:{ readonly id: number; readonly name: string; }

// 使用示例
const user: ReadonlyUser = { id: 1, name: "张三" };
user.name = "李四"; // 编译错误:无法分配到 "name" ,因为它是只读属性

Pick

从类型 T 中选取指定的属性 K 组成新类型

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

// 只选取 id 和 name 属性
type UserInfo = Pick<User, "id" | "name">;
// 等价于:{ id: number; name: string; }

// 使用示例
const userInfo: UserInfo = { id: 1, name: "张三" };

Omit

从类型 T 中排除指定的属性 K 组成新类型

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

// 排除 password 属性
type PublicUser = Omit<User, "password">;
// 等价于:{ id: number; name: string; email: string; }

// 使用示例
const publicUser: PublicUser = { id: 1, name: "张三", email: "zhangsan@example.com" };

Exclude

从联合类型 T 中排除可以赋值给 U 的类型

type Animal = "cat" | "dog" | "bird" | "fish";

// 排除 "bird" 和 "fish"
type Mammal = Exclude<Animal, "bird" | "fish">;
// 等价于:"cat" | "dog"

// 使用示例
const pet: Mammal = "cat"; // 合法
const pet2: Mammal = "bird"; // 编译错误

Extract

从联合类型 T 中提取可以赋值给 U 的类型

type Animal = "cat" | "dog" | "bird" | "fish";

// 提取 "bird" 和 "fish"
type Aquatic = Extract<Animal, "bird" | "fish">;
// 等价于:"bird" | "fish"

// 使用示例
const aquaticPet: Aquatic = "fish"; // 合法
const aquaticPet2: Aquatic = "cat"; // 编译错误

NonNullable

从类型 T 中排除 null 和 undefined

type Value = string | number | null | undefined;

// 排除 null 和 undefined
type NonNullValue = NonNullable<Value>;
// 等价于:string | number

// 使用示例
const value: NonNullValue = "hello"; // 合法
const value2: NonNullValue = null; // 编译错误

ReturnType

获取函数类型 T 的返回值类型

function getUser() {
  return { id: 1, name: "张三", email: "zhangsan@example.com" };
}

// 获取函数返回值类型
type User = ReturnType<typeof getUser>;
// 等价于:{ id: number; name: string; email: string; }

// 使用示例
const user: User = { id: 2, name: "李四", email: "lisi@example.com" };

Parameters

获取函数类型 T 的参数类型组成的元组

function createUser(name: string, email: string) {
  return { id: Date.now(), name, email };
}

// 获取函数参数类型
type CreateUserParams = Parameters<typeof createUser>;
// 等价于:[name: string, email: string]

// 使用示例
const params: CreateUserParams = ["王五", "wangwu@example.com"];
const user = createUser(...params);

ConstructorParameters

获取类构造函数的参数类型组成的元组

class User {
  constructor(public name: string, public email: string) {}
}

// 获取构造函数参数类型
type UserConstructorParams = ConstructorParameters<typeof User>;
// 等价于:[name: string, email: string]

// 使用示例
const params: UserConstructorParams = ["赵六", "zhaoliu@example.com"];
const user = new User(...params);

InstanceType

获取类构造函数的实例类型

class User {
  constructor(public name: string, public email: string) {}
}

// 获取实例类型
type UserInstance = InstanceType<typeof User>;
// 等价于:User

// 使用示例
const user: UserInstance = new User("孙七", "sunqi@example.com");

Record

创建一个以 K 为键, T 为值的映射类型

// 创建字符串到数字的映射
type StringToNumber = Record<string, number>;
// 等价于:{ [key: string]: number }

// 使用示例
const scores: StringToNumber = {
  "张三": 90,
  "李四": 85,
  "王五": 95
};

// 更具体的键类型
type UserRole = "admin" | "user" | "guest";
type RolePermissions = Record<UserRole, string[]>;

const permissions: RolePermissions = {
  admin: ["read", "write", "delete"],
  user: ["read", "write"],
  guest: ["read"]
};

ThisType

指定对象字面量中 this 的类型

// 定义 this 类型
interface Context {
  name: string;
  age: number;
}

// 创建带有 this 上下文的方法集合
const methods: {
  greet(): string;
  getInfo(): string;
} & ThisType<Context> = {
  greet() {
    return `Hello, my name is ${this.name}`; // this 类型为 Context
  },
  getInfo() {
    return `${this.name} is ${this.age} years old`; // this 类型为 Context
  }
};

// 使用示例
const context: Context = { name: "张三", age: 30 };
const boundGreet = methods.greet.bind(context);
console.log(boundGreet()); // 输出:Hello, my name is 张三

DeepPartial

递归将类型 T 的所有属性(包括嵌套属性)变为可选

type DeepPartial<T> = T extends object
  ? { [K in keyof T]?: DeepPartial<T[K]> }
  : T;

// 使用示例
interface User {
  id: number;
  name: string;
  address: {
    street: string;
    city: string;
    zipCode: string;
  };
}

type DeepPartialUser = DeepPartial<User>;
// 所有属性(包括嵌套的 address)都变为可选

const update: DeepPartialUser = {
  address: {
    city: "北京"
  }
};

DeepReadonly

递归将类型 T 的所有属性(包括嵌套属性)变为只读

type DeepReadonly<T> = T extends object
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
  : T;

// 使用示例
interface Config {
  api: {
    url: string;
    timeout: number;
    headers: {
      "Content-Type": string;
    };
  };
}

type DeepReadonlyConfig = DeepReadonly<Config>;
// 所有属性(包括嵌套的 api 和 headers)都变为只读

const config: DeepReadonlyConfig = {
  api: {
    url: "https://api.example.com",
    timeout: 5000,
    headers: {
      "Content-Type": "application/json"
    }
  }
};

config.api.url = "https://new-api.example.com"; // 编译错误:无法修改只读属性

Intersection<T, U>

获取两个类型的交集

type Intersection<T, U> = {
  [K in Extract<keyof T, keyof U>]: T[K] & U[K];
};

// 使用示例
interface A {
  id: number;
  name: string;
  age: number;
}

interface B {
  id: string;
  name: string;
  email: string;
}

type ABIntersection = Intersection<A, B>;
// 等价于:{ id: number & string; name: string & string; }
// 实际结果:{ id: never; name: string; }(因为 number & string 是 never)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐