掌握 TS 這些工具類型,讓你開發事半功倍


一、類型別名

TypeScript 提供了為類型注解設置別名的便捷語法,你可以使用 type SomeName = someValidTypeAnnotation 來創建別名,比如:

type Pet = 'cat' | 'dog';
let pet: Pet;

pet = 'cat'; // Ok
pet = 'dog'; // Ok
pet = 'zebra'; // Compiler error

 

二、基礎知識

為了讓大家能更好地理解並掌握 TypeScript 內置類型別名,我們先來介紹一下相關的一些基礎知識。

2.1 typeof

在 TypeScript 中, typeof 操作符可以用來獲取一個變量聲明或對象的類型。

interface Person {
  name: string;
  age: number;
}

const sem: Person = { name: 'semlinker', age: 30 };
type Sem= typeof sem; // -> Person

function toArray(x: number): Array<number> {
  return [x];
}

type Func = typeof toArray; // -> (x: number) => number[]

 

2.2 keyof

keyof 操作符可以用來一個對象中的所有 key 值:

interface Person {
    name: string;
    age: number;
}

type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" 
type K3 = keyof { [x: string]: Person };  // string | number

 

2.3 in

in 用來遍歷枚舉類型:

type Keys = "a" | "b" | "c"

type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any, c: any }

 

2.4 infer

在條件類型語句中,可以用 infer 聲明一個類型變量並且對它進行使用。

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

 

以上代碼中 infer R 就是聲明一個變量來承載傳入函數簽名的返回值類型,簡單說就是用它取到函數返回值的類型方便之后使用。

2.5 extends

有時候我們定義的泛型不想過於靈活或者說想繼承某些類等,可以通過 extends 關鍵字添加泛型約束。

interface ILengthwise {
  length: number;
}

function loggingIdentity<T extends ILengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

 

現在這個泛型函數被定義了約束,因此它不再是適用於任意類型:

loggingIdentity(3);  // Error, number doesn't have a .length property

 

這時我們需要傳入符合約束類型的值,必須包含必須的屬性:

loggingIdentity({length: 10, value: 3});

 

三、內置類型別名

3.1 Partial

Partial<T> 的作用就是將某個類型里的屬性全部變為可選項 ? 。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

在以上代碼中,首先通過 keyof T 拿到 T 的所有屬性名,然后使用 in 進行遍歷,將值賦給 P ,最后通過 T[P] 取得相應的屬性值。中間的 ? ,用於將所有屬性變為可選。

示例:

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

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}

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

const todo2 = updateTodo(todo1, {
  description: "throw out trash"
});

 

3.2 Required

Required<T> 的作用就是將某個類型里的屬性全部變為必選項。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

以上代碼中, -? 的作用就是移除可選項 ? 。

示例:

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

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

 

3.3 Readonly

Readonly<T> 的作用是將某個類型所有屬性變為只讀屬性,也就意味着這些屬性不能被重新賦值。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

如果將上面的 readonly 改成 -readonly , 就是移除子屬性的 readonly 標識。

示例:

interface Todo {
  title: string;
}

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

todo.title = "Hello"; // Error: cannot reassign a readonly property

 

Readonly<T> 對於表示在運行時將賦值失敗的表達式很有用(比如,當嘗試重新賦值凍結對象的屬性時)。

function freeze<T>(obj: T): Readonly<T>;

 

3.4 Record

Record<K extends keyof any, T> 的作用是將 K 中所有的屬性的值轉化為 T 類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

示例:

interface PageInfo {
  title: string;
}

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

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

 

3.5 Pick

Pick<T, K extends keyof T> 的作用是將某個類型中的子屬性挑出來,變成包含這個類型部分屬性的子類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * 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];
};

 

示例:

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

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

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

 

3.6 Exclude

Exclude<T, U> 的作用是將某個類型中屬於另一個的類型移除掉。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

如果 T 能賦值給 U 類型的話,那么就會返回 never 類型,否則返回 T 類型。最終實現的效果就是將 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

 

3.7 Extract

Extract<T, U> 的作用是從 T 中提取出 U 。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

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

 

如果 T 能賦值給 U 類型的話,那么就會返回 T 類型,否則返回 never 類型。

示例:

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

 

3.8 Omit

Omit<T, K extends keyof any> 的作用是使用 T 類型中除了 K 類型的所有屬性,來構造一個新的類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * 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>>;

 

示例:

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

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

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

 

3.9 NonNullable

NonNullable<T> 的作用是用來過濾類型中的 null 及 undefined 類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T extends null | undefined ? never : T;

 

示例:

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

 

3.10 ReturnType

ReturnType<T> 的作用是用於獲取函數 T 的返回類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

 

示例:

type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // {}
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<any>; // any
type T5 = ReturnType<never>; // any
type T6 = ReturnType<string>; // Error
type T7 = ReturnType<Function>; // Error

 

3.11 InstanceType

InstanceType 的作用是獲取構造函數類型的實例類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Obtain the return type of a constructor function type
 */
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;

 

示例:

class C {
  x = 0;
  y = 0;
}

type T0 = InstanceType<typeof C>; // C
type T1 = InstanceType<any>; // any
type T2 = InstanceType<never>; // any
type T3 = InstanceType<string>; // Error
type T4 = InstanceType<Function>; // Error

 

3.12 ThisType

ThisType<T> 的作用是用於指定上下文對象的類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Marker for contextual 'this' type
 */
interface ThisType<T> { }

 

注意:使用 ThisType<T> 時,必須確保 --noImplicitThis 標志設置為 true。

示例:

interface Person {
    name: string;
    age: number;
}

const obj: ThisType<Person> = {
  dosth() {
    this.name // string
  }
}

 

3.13 Parameters

Parameters<T> 的作用是用於獲得函數的參數類型組成的元組類型。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any 
  ? P : never;

 

示例:

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[]

 

3.14 ConstructorParameters

ConstructorParameters<T> 的作用是提取構造函數類型的所有參數類型。它會生成具有所有參數類型的元組類型(如果 T 不是函數,則返回的是 never 類型)。

定義:

// node_modules/typescript/lib/lib.es5.d.ts

/**
 * Obtain the parameters of a constructor function type in a tuple
 */
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

 

示例:

type A = ConstructorParameters<ErrorConstructor>; // [(string | undefined)?]
type B = ConstructorParameters<FunctionConstructor>; // string[]
type C = ConstructorParameters<RegExpConstructor>; // [string, (string | undefined)?]

 

原文 https://semlinker.com/ts-utility-types/

喜歡這篇文章?歡迎打賞~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM