前言
泛型
是為了構建通用化的組件所設計的,在強類型語言中,泛型
是構建大型復雜系統(tǒng)的主要特性之一穿香,它允許將類型定義通用化亭引,而不是單一的形式。
一皮获、基本使用
function doSomeThing<T>(arg: T): T {
return arg;
}
相比于我們之前學習的類型定義的方式焙蚓,這里我們多了一個<T>
,在TypeScript中,這就叫泛型
,表示的語義為,當你調用這個函數(shù)的時候除了傳遞常用的參數(shù)主届,你也可以傳遞類型赵哲,內部會使用傳遞的這個類型。
比如君丁,我們傳遞一個string
類型:
doSomeThing<string>("mss")
值得注意的是,當你使用了泛型
,TypeScript會默認會通過外部傳入的類型将宪,推斷內部變量或者函數(shù)的返回值的類型绘闷,并且強制內部的類型要符合外部傳入的類型,否則较坛,TypeScript會報錯:
function doSomeThing<T>(arg: T): T {
console.log(arg.length)
return arg;
}
// Property 'length' does not exist on type 'T'
但是我們有的數(shù)據(jù)類型就是存在length
屬性的印蔗,那我們這時應該怎么做呢?比如數(shù)組來說丑勤,TypeScript允許我們直接定義數(shù)組的泛型:
function deArr<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
此時我們訪問length
就是合法的华嘹。
同時,定義數(shù)組的泛型也可以這樣寫法竞,這種方式和上面那種方式是等效的:
function deAnotherArr<T>(arg: Array<T>): Array<T> {
console.log(arg.length);
return arg
}
這種方式也是可以耙厚,完全取決于你個人的喜好。
二岔霸、使用泛型類型
基本使用
function doSomeThing<T>(arg: T): T {
console.log(arg.length)
return arg;
}
let myDoSomeThing: <T>(arg: T) => T = doSomeThing;
傳入的類型參數(shù)薛躬,也可以不用和函數(shù)定義的T
保持一致:
let myDoSomeThing: <U>(arg: U) => U = doSomeThing;
這樣也是可以的。
三呆细、泛型接口
基本使用:
我們首先定義一個泛型
接口:
interface GenericInterFace {
<T>(arg: T): T
}
然后我們這樣使用:
let genericInterFace: GenericInterFace = function get<T>(arg: T):T {
return arg;
}
也可以在定義接口的時候將傳入泛型
的類型:
interface GenericInterFace<T> {
(arg: T): T
}
使用的方式和上面的例子一樣:
let genericInterFace: GenericInterFace = function get<T>(arg: T):T {
return arg;
}
此外型宝,前面的例子里面,當我們使用泛型
的時候絮爷,由于TypeScript編譯器不能推斷傳入的T
的類型趴酣,當然這也不可能推斷,所以當我們試圖在內部訪問length
屬性的時候坑夯,就會報錯岖寞。然后,我們這里可以利用接口渊涝,在編譯之前就給開發(fā)一個友好的提示:
定義一個length
的接口:
interface Lengthwise {
length: number;
}
然后重寫我們前面的doSomeThing
例子:
function doSomeThing<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg;
}
此時就不會報錯慎璧,這里已經(jīng)確保了傳入的參數(shù)必定是有length
屬性的。
四跨释、泛型類
泛型
類在結構上和泛型
接口差不多胸私。
class GenericClass<T> {
name: T
add: (x: T, y:T) => T
}
然后我們可以正常的通過new
關鍵字進行實例化。
let genericClass = new GenericClass();
genericClass.name = 'mss';
當然鳖谈,使用泛型
的一個好處就是你可以傳入任意類型的類型參數(shù):
let genericClass = new GenericClass<string>();
這也是合理的岁疼。
五、泛型的高級用法
1、使用泛型確保訪問對象時不會訪問到對象不存在的屬性捷绒。
定義一個泛型
:
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
注意這里是的keyof
是TypeScript中給我們提供的遍歷對象屬性值的操作符瑰排。
然后我們這樣使用:
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
// 1
getProperty(x, "m");
// Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.
2、類的構造函數(shù)和泛型
一起使用
function create<T>(c: { new (): T }): T {
return new c();
}