TypeScript-generics

前言

泛型是為了構(gòu)建通用化的組件所設(shè)計的,在強(qiáng)類型語言中,泛型是構(gòu)建大型復(fù)雜系統(tǒng)的主要特性之一,它允許將類型定義通用化,而不是單一的形式。

一、基本使用

function doSomeThing<T>(arg: T): T {
  return arg;
}

相比于我們之前學(xué)習(xí)的類型定義的方式,這里我們多了一個<T>,在TypeScript中,這就叫泛型,表示的語義為,當(dāng)你調(diào)用這個函數(shù)的時候除了傳遞常用的參數(shù),你也可以傳遞類型,內(nèi)部會使用傳遞的這個類型。

比如,我們傳遞一個string類型:

doSomeThing<string>("mss")

值得注意的是,當(dāng)你使用了泛型,TypeScript會默認(rèn)會通過外部傳入的類型,推斷內(nèi)部變量或者函數(shù)的返回值的類型,并且強(qiáng)制內(nèi)部的類型要符合外部傳入的類型,否則,TypeScript會報錯:

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

// Property 'length' does not exist on type 'T'

但是我們有的數(shù)據(jù)類型就是存在length屬性的,那我們這時應(yīng)該怎么做呢?比如數(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;
}

也可以在定義接口的時候?qū)魅?code>泛型的類型:

interface GenericInterFace<T> {
  (arg: T): T
}

使用的方式和上面的例子一樣:

let genericInterFace: GenericInterFace = function get<T>(arg: T):T {
  return arg;
}

此外,前面的例子里面,當(dāng)我們使用泛型的時候,由于TypeScript編譯器不能推斷傳入的T的類型,當(dāng)然這也不可能推斷,所以當(dāng)我們試圖在內(nèi)部訪問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屬性的。

四、泛型類

泛型類在結(jié)構(gòu)上和泛型接口差不多。

class GenericClass<T> {
  name: T
  add: (x: T, y:T) => T
}

然后我們可以正常的通過new關(guān)鍵字進(jìn)行實例化。

let genericClass = new GenericClass();
genericClass.name = 'mss';

當(dāng)然,使用泛型的一個好處就是你可以傳入任意類型的類型參數(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、類的構(gòu)造函數(shù)和泛型一起使用

function create<T>(c: { new (): T }): T {
  return new c();
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容