概述

这篇文章会带着我们去阅读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

总结

  • 根本上比较常用的就这些还有许多内置东西类型,我就不再这里一一列举了,假如你能把上面这些看懂,看其他的也不成问题,一样的学习方法和解析思路。
  • 受人以渔,下面是我学习参考的材料:
    • ts 官方文档
    • 《Typescirpt入门与实战》6.7-6.8