掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
在實(shí)際應(yīng)用中可能會(huì)遇到求最小值的問(wèn)題,比如求數(shù)組中的最小值。

在 ts 中的就需要寫(xiě)兩種方式,一種針對(duì) number,另外一種針對(duì)字符串。
這樣寫(xiě)不利于代碼重用,項(xiàng)目較大時(shí),性能較差,同時(shí)工作效率也低,所以在 ts 中引入了泛型概念。
function getMin1(arr:number[]):number {
let min = arr[0]
for (var i = 1; i < arr.length; i++){
if (min > arr[i]) {
min = arr[i]
}
}
return min
}
console.log(getMin1([1, 2, 3, 4]));
function getMin2(arr:string[]):string {
let min = arr[0]
for (var i = 1; i < arr.length; i++){
if (min > arr[i]) {
min = arr[i]
}
}
return min
}
console.log(getMin2(['a', 'b', 'c']));泛型英文是 generics ,是指在定義函數(shù)、接口或類(lèi)的時(shí)候,不預(yù)先指定具體的類(lèi)型,而是在使用的時(shí)候再指定類(lèi)型的一種。
定義方式:
function fnName(arg:T,...):T{
return ...
}
泛型變量通常用 T 來(lái)表示,T可以表示任何類(lèi)型。
所以呢,我們可以將上述實(shí)例修改成以下代碼:
function getMin(arr: T[]): T{
let min = arr[0]
for (var i = 1; i < arr.length; i++){
if (min > arr[i]) {
min = arr[i]
}
}
return min
}
getMin([1, 2, 3, 4])
getMin(['a', 'b', 'c', 'd'])
上述代碼中,T 的主要作用就是幫助我們來(lái)捕獲用戶傳入的類(lèi)型,比如 :number 或 string 。另外編譯器也會(huì)根據(jù)傳入的參數(shù)自動(dòng)地幫助我們進(jìn)行類(lèi)型推斷,然后把 T 設(shè)置為它的類(lèi)型,所以可以忽略類(lèi)型的傳入,如:
getMin([1, 2, 3, 4])
getMin(['a', 'b', 'c', 'd'])
在一些復(fù)雜的情況下,為了防止編譯器自動(dòng)推斷類(lèi)似失敗,盡可能地將類(lèi)型傳入,防止出錯(cuò)。
泛型函數(shù)的類(lèi)型和非泛型函數(shù)的類(lèi)型有什么不同?
它們看著很相似,泛型函數(shù)類(lèi)型前面有一個(gè)類(lèi)型參數(shù) 。
對(duì)于泛型函數(shù)類(lèi)型還有以下特性:
a>、泛型函數(shù)類(lèi)型可以有多個(gè)參數(shù)
function fn(arg1: T, arg2: U) {
return arg1
}
b>、泛型函數(shù)可以使用不同的泛型參數(shù)名
function fn(arg1: T) {
return arg1
}
let Fn:(arg1: M) => M = fn
c>、可以使用帶有對(duì)象字面量的方式定義泛型函數(shù)
function fn(arg1: T) {
return arg1
}
let Fn: {(arg: T): T} = fn
在使用對(duì)象字面量的方式定義泛型函數(shù)時(shí),對(duì)象的形式可以替換成接口的形式,改為:
let Fn: { (arg: T): T } = fn
//替換為
interface FnInter{
(arg: T): T
}
let Fn: FnInter = fn 這種方式存在問(wèn)題:函數(shù)對(duì)數(shù)據(jù)類(lèi)型一無(wú)所知,無(wú)法使用某個(gè)數(shù)據(jù)類(lèi)型進(jìn)行操作。所以需要改良下,將類(lèi)型作為參數(shù)傳入,如:
interface FnInter{
(arg:T): T
}
let Fn: FnInter= fn
這樣我們就能清楚地知道使用的具體是那個(gè)泛型類(lèi)型。
我們將整個(gè)接口當(dāng)做泛型參數(shù),就叫做泛型接口。它的優(yōu)點(diǎn)就是我們能清除知道參數(shù)的數(shù)據(jù)類(lèi)型,接口內(nèi)的成員也能知道參數(shù)的具體類(lèi)型。
除了有泛型接口之外,還有接口類(lèi)。泛型類(lèi)與泛型函數(shù)差不多。
語(yǔ)法格式為:
class 名稱(chēng){}
new 類(lèi)名<類(lèi)型>()
class GetMin{
arr: T[] = []
add(ele:T) {
this.arr.push(ele)
}
getMin(): T{
var min = this.arr[0]
for (var i = 0; i < this.arr.length; i++){
if (min > this.arr[i]) {
min = this.arr[i]
}
}
return min
}
}
let gMin1 = new GetMin()
gMin1.add(1)
gMin1.add(5)
console.log(gMin1.getMin());//1
let gMin2 = new GetMin()
gMin2.add('a')
gMin2.add('b')
console.log(gMin2.getMin());//2
泛型功能確實(shí)挺強(qiáng)大的,但它也不是萬(wàn)能的。比如:
function getLength(val: T): number {
return val.length;
}
錯(cuò)誤信息提示:類(lèi)型“T”上不存在屬性“l(fā)ength”。
原因是只有字符串、數(shù)組才有 length 屬性,對(duì)于數(shù)字、對(duì)象沒(méi)有 length 屬性,所以報(bào)錯(cuò)了。解決辦法是要保證傳入的數(shù)據(jù)類(lèi)型有 length 屬性,所以需要使用泛型約束。
泛型約束主要是通過(guò)接口 + extends 關(guān)鍵字來(lái)實(shí)現(xiàn)約束。
interface ILen{
length:number
}
function getLength(val: T): number {
return val.length;
}
console.log(getLength("abcd"));
console.log(getLength(1)); //錯(cuò)誤提示:類(lèi)型“number”不滿足約束“ILen”。 使用泛型約束的優(yōu)點(diǎn)是幫我們自動(dòng)檢測(cè)傳入的值是否符合約束類(lèi)型的值,不滿足時(shí)就會(huì)有錯(cuò)誤提示。
在 typeScript 2.3 以后,可以為泛型中的類(lèi)型參數(shù)指定默認(rèn)類(lèi)型,當(dāng)使用泛型時(shí)沒(méi)有指定參數(shù)類(lèi)型,并且編輯器從實(shí)際參數(shù)中也無(wú)法推斷出數(shù)據(jù)類(lèi)型時(shí),就使用默認(rèn)類(lèi)型。
使用簡(jiǎn)單:
interface P{
name:T
}
let p1: P = { name: "小姐姐" }
let p2: P= { name: 18 }
在 typeScript 2.8 中,引入了條件類(lèi)型,我們可以根據(jù)某些條件得到不同的類(lèi)型,此處的條件是類(lèi)型兼容性約束。
條件類(lèi)型會(huì)以一定條件表達(dá)式進(jìn)行類(lèi)型關(guān)系檢測(cè),從而在兩種類(lèi)型中選擇其一:
使用語(yǔ)法:
T extends U ? X : Y
以上表達(dá)式的意思是:若 T 能夠賦值給 U,那么類(lèi)型是 X,否則為 Y。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流