內置工具類型 -- 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就是一個空的泛型接口。

相關文章
相關標籤/搜索