泛型
介紹
軟件工程中察藐,我們不僅要創(chuàng)建一致的定義良好的 API,同時也要考慮可重用性转培。 組件不僅能夠支持當前的數(shù)據(jù)類型浆竭,同時也能支持未來的數(shù)據(jù)類型,這在創(chuàng)建大型系統(tǒng)時為你提供了十分靈活的功能删窒。可以使用泛型來創(chuàng)建可重用的組件肌索,一個組件可以支持多種類型的數(shù)據(jù)特碳。
泛型之 Hello World
這個函數(shù)會返回任何傳入它的值
function identity<T>(arg: T): T {
return arg;
}
有兩種方法使用:
1.傳入所有的參數(shù),包含類型參數(shù):
let output = identity<string>("myString"); // type of output will be 'string'
2.類型推論 -- 編譯器會根據(jù)傳入的參數(shù)自動地幫助我們確定 T 的類型
let output = identity("myString"); // type of output will be 'string'
使用泛型變量
把泛型變量 T 當做類型的一部分使用站宗,而不是整個類型益愈,增加了靈活性
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
泛型類型
泛型接口:
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
除了泛型接口,我們還可以創(chuàng)建泛型類敏释。 注意摸袁,無法創(chuàng)建泛型枚舉和泛型命名空間。
泛型類
泛型類看上去與泛型接口差不多靠汁。 泛型類使用( <>)括起泛型類型湿蛔,跟在類名后面阳啥。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
泛型類指的是實例部分的類型财喳,所以類的靜態(tài)屬性不能使用這個泛型類型。
泛型約束
我們想要限制函數(shù)去處理任意帶有.length 屬性的所有類型耳高。 只要傳入的類型有這個屬性,我們就允許概荷,就是說至少包含這一屬性。 為此误证,我們需要列出對于 T 的約束要求修壕。
為此,我們定義一個接口來描述約束條件慈鸠。 創(chuàng)建一個包含 .length 屬性的接口,使用這個接口和 extends 關鍵字來實現(xiàn)約束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
現(xiàn)在這個泛型函數(shù)被定義了約束譬巫,因此它不再是適用于任意類型:
loggingIdentity(3); // Error, number doesn't have a .length property
在泛型約束中使用類型參數(shù)
function getProperty(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
在泛型里使用類類型
在 TypeScript 使用泛型創(chuàng)建工廠函數(shù)時督笆,需要引用構造函數(shù)的類類型
function create<T>(c: { new (): T }): T {
return new c();
}
一個更高級的例子,使用原型屬性推斷并約束構造函數(shù)與類實例的關系。
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!