likes
comments
collection
share

TS内置工具类型,看这篇足矣。

作者站长头像
站长
· 阅读数 69

概述

这篇文章会带着大家去阅读TS内置工具类型源码,也会对基本对使用做介绍。这些工具类型的定义位于TypeScript语言安装目录下的“lib/lib.es5.d.ts”文件中。结合源码学习,一能够掌握这些工具类型,同时也能学习到一些类型定义的技巧。

TS内置工具类型

Partial<T>

基本使用

该工具类型能够构造一个新类型,并将实际类型参数T中的所有属性变为可选属性。示例如下:

interface A {
    x: number;
    y: number;
}

type T = Partial<A>; // { x?: number; y?: number; }

const a: T = { x: 0, y: 0 };
const b: T = { x: 0 };
const c: T = { y: 0 };
const d: T = {}

源码解析

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

tips:这个很简单吧,遍历T将其所有属性转换为可选属性。

Required<T>

基本使用

该工具类型能够构造一个新类型,并将实际类型参数T中的所有属性变为必选属性。示例如下:

interface A {
    x?: number;
    y: number;
}

type T0 = Required<A> // { x: number; y: number }

源码解析

/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

tips:遍历T将可选属性转换为必选属性。

Readonly<T>

基本使用

该工具类型能够构造一个新类型,并将实际类型参数T中的所有属性变为只读属性。示例如下:

interface A {
    x?: number;
    y: number;
}

// { readonly x: number; readonly y: number; }
type T = Readonly<A>;

const a: T = { x: 0, y : 0};
a.x = 1; // 编译错误,不允许修改
a.y = 1; // 编译错误,不允许修改

源码解析

/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

tips:遍历T将所有属性转换为只读属性。

Record<Keys,Type>

基础使用

该工具类型能够使用给定的对象属性名类型和对象属性类型创建一个新的对象类型。

interface CatInfo {
    age: number;
    breed: string;
}

type CatName = "miffy" | "boris" | "mordred";

const cats: Record<CatName, CatInfo> = {
    miffy: { age: 10, breed: "Persian" },
    boris: { age: 5, breed: "Maine Coon" },
    mordred: { age: 16, breed: "British Shorthair" },
};

cats.boris; // { age: number, breed: string }

源码解析

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

tips:将所有K的属性限定为T类型

Pick<Type, Keys>

基本使用

该工具类型能够从已有对象类型中选取给定的属性及其类型,然后构建出一个新的对象类型。

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

// { title: string; completed: string }
type TodoPreview = Pick<Todo, "title" | "completed">; 

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

源码解析

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

tips:只定义K中的属性

Exclude<UnionType, ExcludedMembers>

基础使用

该工具类型能够从类型T中剔除所有可以赋值给类型U的类型。示例如下:

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
         

源码解析

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

tips:分布式条件类型具有一种特殊的行为,那就是在使用实际类型参数实例化分布式条件类型时,如果实际类型参数T为联合类型,那么会将分布式条件类型展开为由子条件类型构成的联合类型。这看起来可能有些疑惑,我直接上个例子大家就懂了,示例如下:

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// 等价于
type T0 = Exclude<"a", "a"> | Exclude<"b", "a"> | Exclude<"c", "a">

Omit<Type, Keys>

基础使用

Omit<T, K>工具类型与Pick<T, K>工具类型是互补的,它能够从已有对象类型中剔除给定的属性,然后构建出一个新的对象类型。

interface Todo {
    title: string;
    description: string;
    completed: boolean;
    createdAt: number;
}

// { title: string, completed: boolean, createdAt: number }
type TodoPreview = Omit<Todo, "description">; 

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

// { title: string, description: string }
type TodoInfo = Omit<Todo, "completed" | "createdAt">;

const todoInfo: TodoInfo = {
    title: "Pick up kids",
    description: "Kindergarten closes at 5pm",
};

源码解析

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

tips:这个我就不多讲了,就是 pick 和 exclude 的结合,把上面这两个的使用和源码理解一下,这个自己就能推导了。

Extract<Type, Union>

基础使用

Extract<T, U>工具类型与Exclude<T, U>工具类型是互补的,它能够从类型T中获取所有可以赋值给类型U的类型。示例如下:

type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

type T1 = Extract<string | number | (() => void), Function>; // () => void

源码解析

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;

tips:和 Exclude 原理相同,就是反过来了。

NonNullable<Type>

基础使用

该工具类型能够从类型T中剔除null类型和undefined类型并构造一个新类型,也就是获取类型T中的非空类型。示例如下:

type T0 = NonNullable<string | number | undefined>; // string | number
      
type T1 = NonNullable<string[] | null | undefined>; // string[]

源码解析

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T & {};

Parameters<Type>

基础使用

该工具类型能够获取函数类型T的参数类型并使用参数类型构造一个元组类型。示例如下:

declare function f1(arg: { a: number; b: string }): void;
 
type T0 = Parameters<() => string>; // []
     
type T1 = Parameters<(s: string) => void>; // [s: string]
     
type T2 = Parameters<<T>(arg: T) => T>; // [arg: unknown]

// [arg: {
//     a: number;
//     b: string;
// }]
type T3 = Parameters<typeof f1>;

// unknown[]
type T4 = Parameters<any>;
     
// never
type T5 = Parameters<never>;

type T6 = Parameters<string>; // never
// Type 'string' does not satisfy the constraint '(...args: any) => any'.
     
type T7 = Parameters<Function>; // never
// Type 'Function' does not satisfy the constraint '(...args: any) => any'.
//   Type 'Function' provides no match for the signature '(...args: any): any'.

源码分析

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

此例中,使用infer声明定义了可推断的类型变量P。当编译器解析该条件类型时,会根据T的实际类型来推断类型变量 P 的实际类型。所以满足条件时 P 也就是 args 。

总结

  • 基本上比较常用的就这些还有很多内置工具类型,我就不再这里一一列举了,如果你能把上面这些看懂,看其他的也不成问题,一样的学习方法和解析思路。
  • 受人以渔,下面是我学习参考的资料:
转载自:https://juejin.cn/post/7147301855775719461
评论
请登录