最近寫類型定義時,發現想要實現的類型不知道該用什麼方法實現。也發現以前的代碼裏寫了一些不優雅的類型定義。看了Utility以後以爲仍是本身知道的太少了,想要用的這裏都有了。而後去看了一下他們的源碼實現,發現也不難。這裏分享一下本身的學習筆記。數組
Partial<T>
將T中全部屬性轉換爲可選屬性。返回的類型能夠是T的任意子集。bash
interface Todo {
title: string;
description: string;
done: boolean;
}
function updateTodo(todo: Todo, newTodo: Partial<Todo>) {
return { ...todo, ...newTodo };
}
const todo: Todo = {
title: 'First Todo',
description: 'this is the first todo',
done: false
};
updateTodo(todo, { done: true });
複製代碼
源碼:函數
type Partial<T> = { [P in keyof T]?: T[P]; };
複製代碼
解析: keyof T, 索引類型查詢操做符。 對於任何類型 T, keyof T 的結果爲 T 上已知的公共屬性名的聯合。學習
type todoKeys = keyof Todo; // "title" | "description" | "done"
複製代碼
keyof 取到 T 中的屬性名,in 操做符遍歷屬性名。可選屬性操做符 ? 將全部屬性定義爲可選屬性。ui
Required<T>
經過將T的全部屬性設置爲必選屬性來構造一個新的類型。與Partial相對。this
interface Example {
a?: string;
b?: string;
}
const example1: Example = { a: 'aaa' }; // right
const example2: Required<Example> = { a: 'aaa' };
// error: Property 'b' is missing in type '{ a: string; }' but required in type 'Required<Example>'
複製代碼
源碼:spa
type Required<T> = { [P in keyof T]-?: T[P]; };
// 與partial類似,遍歷T中屬性,並將全部屬性置爲必選屬性
複製代碼
Readonly<T>
將T中全部屬性設置爲只讀。翻譯
interface Todo {
title: string;
}
const todo: Readonly<Todo> = { title: 'First Todo' };
todo.title = 'New Title'; // Cannot assign to 'title' because it is a read-only property.
複製代碼
源碼:code
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
複製代碼
Record<K,T>
構造一個類型,該類型具備一組屬性K,每一個屬性的類型爲T。可用於將一個類型的屬性映射爲另外一個類型。cdn
type TodoProperty = 'title' | 'description';
type Todo = Record<TodoProperty, string>;
const todo: Todo = {
title: 'First Todo',
description: 'this is the first todo'
};
複製代碼
源碼:
type Record<K extends keyof any, T> = { [P in K]: T; };
複製代碼
Pick<T,K>
經過在T中抽取一組屬性K構建一個新類型。
interface Todo {
title: string;
description: string;
done: boolean;
}
type TodoBase = Pick<Todo, 'title' | 'done'>;
const todo: TodoBase = {
title: 'First Todo',
done: false
};
複製代碼
源碼:
type Pick<T, K extends keyof T> = { [p in K]: T[p] }; // K是T的屬性集合的子集
複製代碼
Exclude<T,U>
從T中排除可分配給U的屬性,剩餘的屬性構成新的類型。
type T0 = 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,U>
從T中抽出可分配給U的屬性構成新的類型。與Exclude相反。
type T0 = Extract<'a' | 'b' | 'c', 'a'>; // "a"
// 多參數類型約束
interface StringItem {
type: 'stringItem'
value: string;
}
interface NumberItem {
type: 'numberItem'
value: number;
}
type Item = StringItem | NumberItem;
function addCase<IType extends Item['type']>(type: IType, value: Extract<Item, { type: IType }>['value']): void {
console.log(type, ':', value);
}
addCase('stringItem', 'value1'); // right
addCase('numberItem', 2); // right
addCase('stringItem', 1); // error:類型「1」的參數不能賦給類型「string」的參數
addCase('numberItem', 'value2'); // error:類型「"value2"」的參數不能賦給類型「number」的參數
複製代碼
源碼:
type Extract<T, U> = T extends U ? T : never;
複製代碼
Omit<T,K>
從T中取出除去K的其餘全部屬性。與Pick相對。
interface Todo {
title: string;
description: string;
done: boolean;
}
type TodoBase = Omit<Todo, 'description'>;
const todo: TodoBase = {
title: 'First Todo',
done: false
};
複製代碼
源碼:
// 結合Exclude和Pick實現
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
複製代碼
NonNullable<T>
去除T中的 null 和 undefined 類型。
type T0 = NonNullable<number | string | undefined> // number | string
type T1 = NonNullable<number | null | undefined> // number
複製代碼
源碼:
type NonNullable<T> = T extends null | undefined ? never : T;
複製代碼
Parameters<T>
返回類型爲T的函數的參數類型所組成的數組。
declare function f1(arg: { a: number, b: string }): void
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<(<T>(arg: T) => T)>; // [unknown]
type T4 = Parameters<typeof f1>; // [{ a: number, b: string }]
type T5 = Parameters<any>; // unknown[]
type T6 = Parameters<never>; // never
type T7 = Parameters<string>; // Error: 類型「string」不知足約束「(...args: any) => any」
type T8 = Parameters<Function>; // Error: 類型「Function」不知足約束「(...args: any) => any」。類型「Function」提供的內容與簽名「(...args: any): any」不匹配
複製代碼
源碼:
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
複製代碼
解析: 條件類型中的類型推斷(高級類型章節)(原文檔截圖):
在條件類型中使用extends時,能夠聲明一個infer來表示有一個類型變量須要推斷。這個可推斷的類型變量能夠在條件類型的true分支上引用。同一個類型變量可能有多個推斷的位置。
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>; // string
type T11 = Foo<{ a: string, b: number }>; // string | number
複製代碼
ReturnType<T>
function T的返回類型。
declare function f1(): { a: number, b: string }
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<typeof f1>; // { a: number, b: string }
type T5 = ReturnType<any>; // any
type T6 = ReturnType<never>; // any
type T7 = ReturnType<string>; // Error: 類型「string」不知足約束「(...args: any) => any」
type T8 = ReturnType<Function>; // Error:類型「Function」不知足約束「(...args: any) => any」。類型「Function」提供的內容與簽名「(...args: any): any」不匹配
複製代碼
源碼:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
複製代碼
InstanceType<T>
返回構造函數類型T的實例類型。
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:類型「string」不知足約束「new (...args: any) => any」
type T4 = InstanceType<Function>; // error:類型「Function」不知足約束「new (...args: any) => any」。類型「Function」提供的內容與簽名「new (...args: any): any」不匹配
複製代碼
源碼:
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
複製代碼