内置工具类型 -- Typescript类型编程篇(5)

Partial<T>

Partial用于将类型中全部属性变为可选类型:typescript

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

const todo1: Todo = {
  title: "organize desk",
  description: "clear clutter",
};

const todo2: Partial<Todo> = {
  description: "throw out trash",
};
复制代码

实现源码:函数

type Partial<T> = {
    [P in keyof T]?: T[P];
};
复制代码

Required<T>

Required用于将类型全部属性变为必需类型:ui

interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 }; // OK
const obj2: Required<Props> = { a: 5 }; // Error: property 'b' missing
复制代码

实现源码:this

type Required<T> = {
    [P in keyof T]-?: T[P];
};
复制代码

Readonly<T>

Readonly用于将类型中全部属性变成只读类型:spa

interface Todo {
  title: string;
}

const todo: Readonly<Todo> = {
  title: "Delete inactive users"
};

todo.title = "Hello"; // Error: cannot reassign a readonly property
复制代码

实现源码:code

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

复制代码

Record<T, K>

Record用于将T中全部的属性转换为K类型:接口

interface PageInfo {
  title: string;
}

type Page = "home" | "about" | "contact";

const x: Record<Page, PageInfo> = {
  about: { title: "about" },
  contact: { title: "contact" },
  home: { title: "home" },
};
复制代码

实现源码:ip

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
复制代码

Exclude<T, K>

Exclude用于筛选全部在T中,但不在K中的属性:ci

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 复制代码

实现源码:源码

type Exclude<T, U> = T extends U ? never : T;
复制代码

Extract<T, K>

ExtractExclude有些相似,用于筛选既在T中,又在K中的属性:

type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void
复制代码

实现源码:

type Extract<T, U> = T extends U ? T : never;
复制代码

Pick<T, K>

Pick用于返回从T中筛选出K包含的属性所组成的类型:

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

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

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
复制代码

实现源码:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
复制代码

Omit<T, K>

Pick相反,忽略K中包含的属性:

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

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

const todo: TodoPreview = {
  title: "Clean room",
  completed: false
};
复制代码

实现源码:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
复制代码

能够看到,Omit类型就是对以前提到的PickExclude的进一步封装。

NonNullable<T>

NonNullable用于筛选出T中不是null或者undefined的全部类型:

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

实现源码:

type NonNullable<T> = T extends null | undefined ? never : T;
复制代码

Parameters<T>

Parameters用于筛选函数全部的参数类型,并返回一个由这些参数类型构成的元组:

type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<<T>(arg: T) => T>; // [unknown]
复制代码

实现源码:

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

能够看到T被约束必须为函数类型,若是传入一个非函数类型会报错。

ReturnType<T>

ReturnType用于获取函数返回值类型:

type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // unknown
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
复制代码

实现源码:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
复制代码

T一样被约束必须为函数类型。

ConstructorParameters<T>

ConstructorParametersParameters十分类似,用于获取构造函数的全部参数类型:

class Person {
  constructor(name: string, age: number) {}
}

type T0 = ConstructorParameters<typeof Person>; // [string, number]
复制代码

实现源码:

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
复制代码

T被约束为必须为构造函数。

InstanceType<T>

InstanceType用于获取构造函数的返回值:

class Person {
  constructor(name: string, age: number) {}
}

type T0 = InstanceType<typeof Person>; // Person
复制代码

实现源码:

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
复制代码

T一样被约束为必须为构造函数。

ThisParameterType<T>

ThisParameterType用于获取函数的this参数类型。若是函数未指定this参数,返回unknown,须要开启strictFunctionTypes才能工做:

function toHex(this: Number) {
  return this.toString(16);
}

type T0 = ThisParameterType<typeof toHex>; // Number
复制代码

实现源码:

type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any
  ? U
  : unknown;
复制代码

OmitThisParameter<T>

OmitThisParameter用于删除函数中的this参数,须要开启strictFunctionTypes才能工做:

function toHex(this: Number, others: any) {
  return this.toString(16);
}

type T0 = typeof toHex; // function toHex(this: Number, others: any): string
type T1 = OmitThisParameter<typeof toHex>; // (others: any) => string
复制代码

实现源码:

type OmitThisParameter<T> = unknown extends ThisParameterType<T>
  ? T
  : T extends (...args: infer A) => infer R
  ? (...args: A) => R
  : T;
复制代码

ThisType<T>

ThisType并不会转换类型,而是用于标记函数中this的类型,相似于指定this参数。须要开启noImplicitThis才能工做:

type ObjectDescriptor<D, M> = {
  data?: D;
  methods?: M & ThisType<D & M>; // 标记方法的this类型
};

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
  let data: object = desc.data || {};
  let methods: object = desc.methods || {};
  return { ...data, ...methods } as D & M;
}

let obj = makeObject({
  data: { x: 0, y: 0 },
  methods: {
    moveBy(dx: number, dy: number) {
      this.x += dx; // ts能识别this类型 
      this.y += dy; 
    }
  }
});
复制代码

methods使用ThisType指定this。因此makeObject函数调用时,ts就能推断出methods中的函数this类型为{ x: number, y: number } & { moveBy(dx: number, dy: number): number }

在源码中,ThisType就是一个空的泛型接口。

相关文章
相关标签/搜索