Skip to content

TS中一些内置的工具函数实现和示例 Documentation - Utility Types

Partial

Partial<T> 将类型 T 中的所有属性转换为可选属性。

typescript
type Partial<T> = {
    [P in keyof T]?: T[P];
};

首先通过 keyof T 拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P] 取得相应的属性值的类。中间的 ? 号,用于将所有属性变为可选。


eg.

typescript
interface UserInfo {
    id: string;
    name: string;
}
// error:Property 'id' is missing in type '{ name: string; }' but required in type 'UserInfo'
const xiaoming: UserInfo = {
    name: 'xiaoming'
}

**使用 Partial<T>**

typescript
type NewUserInfo = Partial<UserInfo>;
const xiaoming: NewUserInfo = {
    name: 'xiaoming'
}

// => 相当于
interface NewUserInfo {
    id?: string;
    name?: string;
}

Partial<T> 有个局限性,就是只支持处理第一层的属性,如果我的接口定义是这样的

typescript
interface UserInfo {
    id: string;
    name: string;
    fruits: {
        appleNumber: number;
        orangeNumber: number;
    }
}

type NewUserInfo = Partial<UserInfo>;

// Property 'appleNumber' is missing in type '{ orangeNumber: number; }' but required in type '{ appleNumber: number; orangeNumber: number; }'.
const xiaoming: NewUserInfo = {
    name: 'xiaoming',
    fruits: {
        orangeNumber: 1,
    }
}

第二层以后就不会处理了,需要自己实现.

DeepPartial

typescript
type DeepPartial<T> = {
     // 如果是 object,则递归类型
    [U in keyof T]?: T[U] extends object
      ? DeepPartial<T[U]>
      : T[U]
};

type PartialedWindow = DeepPartial<T>; // 现在T上所有属性都变成了可选啦

Required

将类型 T 中的所有属性转换为必选属性

typescript
type Required<T> = {
    [P in keyof T]-?: T[P];
};

Partial 和 Required 的唯一差异是在索引类型签名处的可选修饰符,Partial 是 ?,即标记属性为可选,而 Required 则是 -?,相当于在原本属性上如果有 ? 这个标记,则移除它

typescript
// Partial 也可以显示 加上 +? 这种表示方法
type Partial<T> = {
    [P in keyof T]+?: T[P];
};

eg.

typescript
interface PartialPerson {
    name?: string;
    age?: number;
}

type RequiredPerson = Required<PartialPerson>;
// RequiredPerson 的类型为 { name: string; age: number; }

Readonly

将类型 T 中的所有属性转换为只读属性

typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
typescript
interface Person {
    name: string;
    age: number;
}

type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson 的类型为 { readonly name: string; readonly age: number; }

Record

Record<K extends keyof any, T> 创建一个具有指定属性类型 T 的对象,其属性由类型 K 中的所有属性组成。

K extends keyof any 即为键的类型,这里使用 extends keyof any 标明,

  1. 传入的 K 可以是单个类型,也可以是联合类型,
  2. 而 T 即为属性的类型
typescript
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
typescript
// 键名均为字符串,键值类型未知
type Record1 = Record<string, unknown>;
// 键名均为字符串,键值类型任意
type Record2 = Record<string, any>;
// 键名为字符串或数字,键值类型任意
type Record3 = Record<string | number, any>;
typescript
type Numbers = 'one' | 'two' | 'three';
type NumberMap = Record<Numbers, number>;
// NumberMap 的类型为 { one: number; two: number; three: number; }
typescript
interface PageInfo {
  title: string
}

type Page = 'home' | 'about' | 'contact'

const x: Record<Page, PageInfo> = {
  about: { title: 'about' },
  contact: { title: 'contact' },
  home: { title: 'home' }
}


type Test = Record<Page, PageInfo>
// 相当于 => 
// type Test = {
//   home: PageInfo;
//   about: PageInfo;
//   contact: PageInfo;
// }

Pick

Pick<T, K> 从类型 T 中选择指定的一组属性 K 构造一个新的类型。 From T pick a set of properties K

typescript
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Pick,它接受两个泛型参数,T 即是我们会进行结构处理的原类型(一般是对象类型),而 K 则被约束为 T 类型的键名联合类型。

typescript
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;
typescript
interface Person {
    name: string;
    age: number;
    address: string;
}

type PersonInfo = Pick<Person, 'name' | 'age'>;
// PersonInfo 的类型为 { name: string; age: number; }
typescript
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Pick 是保留这些传入的键,比如从一个庞大的结构中选择少数字段保留,需要的是这些少数字段,而 Omit 则是移除这些传入的键,也就是从一个庞大的结构中剔除少数字段,需要的是剩余的多数部分。

Omit

Omit<T, K extends keyof any> 从类型 T 中移除指定的属性 K 构造一个新的类型。

typescript
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
typescript
interface Person {
    name: string;
    age: number;
    address: string;
}

type PersonWithoutAddress = Omit<Person, 'address'>;
// PersonWithoutAddress 的类型为 { name: string; age: number; }
typescript
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit<Todo, "description">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Exclude

Exclude<T, U> 从类型 T 中排除可以赋值给 U 的类型

typescript
type Exclude<T, U> = T extends U ? never : T;
typescript
type MyType = Exclude<string | number | boolean, boolean>;
// MyType 的类型为 string | number
typescript
type Tmp1 = Exclude<1, 2> // 1
type Tmp2 = Exclude<1 | 2, 2> // 1
type Tmp3 = Exclude<1 | 2 | 3, 2 | 3> // 1
type Tmp4 = Exclude<1 | 2 | 3, 2 | 4> // 1 | 3

// 注意,这里是分布式条件类型
typescript
type T0 = Exclude<'a' | 'b' | 'c', 'a'> // "b" | "c"
type T1 = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // "c"
type T2 = Exclude<string | number | (() => void), Function> // string | number

Extract

Extract<T, U> 从类型 T 中提取可以赋值给 U 的类型

typescript
type Extract<T, U> = T extends U ? T : never;
typescript
type MyType = Extract<string | number | boolean, boolean>;
// MyType 的类型为 boolean
typescript
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () =>void

ReturnType

**ReturnType<T> **** **用于获取函数类型 T 的返回(值)类型

typescript
type ReturnType<T extends (...args: any[]) => any> = T extends (
  ...args: any[]
) => infer R
  ? R
  : any

eg.

typescript
type Func = (value: number=> string;
const foo: ReturnType<Func= "hello";
// ReturnType获取到 Func 的返回值类型为 string,
// 所以,foo 也就只能被赋值为字符串了
typescript
function greet(): string {
    return "Hello";
}

type GreetReturnType = ReturnType<typeof greet>; // 结果为 string

NonNullable

**NonNullable<T>**: 从类型 T 中移除 nullundefined

typescript
type NonNullable<T> = T extends null | undefined ? never : T;

// 最新版本 改为了这样了
type NonNullable<T> = T & {};

eg.

typescript
type MyType = string | null | undefined;
type NonNullableMyType = NonNullable<MyType>; // 结果为 string
typescript
type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]

Parameters

**Parameters<T>** 获取函数类型 T 的参数类型组成的元组类型

typescript
type Parameters<T extends (...args: any) => any> = T extends (
  ...args: infer P
) => any
  ? P
  : never

eg.

typescript
function greet(name: string, age: number): void {
  console.log(`Hello, ${name}! You are ${age} years old.`)
}

type GreetParameters = Parameters<typeof greet> 
// 结果为 [string, number]
typescript
type A = Parameters<() => void> // []
type B = Parameters<typeof Array.isArray> // [any]
type C = Parameters<typeof parseInt> // [string, number | undefined]
type D = Parameters<typeof Math.max> // number[]