TypeScript-泛型-2-泛型約束
?鬼哥本周將通過(guò)幾篇優(yōu)秀的Typescript文章,讓大家學(xué)習(xí)到Typescript一些高級(jí)的用法,讓大家對(duì)Typescript更加的深入理解,并且更好實(shí)踐到工作當(dāng)中,【一共五篇文章】,關(guān)注我們一起完成這個(gè)系列的學(xué)習(xí)
原文:https://github.com/leslie1943
?
?? 泛型約束?
?有時(shí)我們可能希望限制每個(gè)類型變量接收的類型數(shù)量,這就是泛型約束的作用.
?
?? 4.1 確保屬性存在
希望類型變量對(duì)應(yīng)的類型上存在某些屬性. 這時(shí), 除非我們顯式地將特定屬性定義為類型變量, 否則編譯器不會(huì)知道他們的存在. 一個(gè)很好的例子是在處理字符串或數(shù)組時(shí), 我們會(huì)假設(shè) length 屬性是可用的. 讓我們?cè)俅问褂?identity 函數(shù)并嘗試輸出參數(shù)的長(zhǎng)度.
function identity<T>(arg: T): T {
console.info(arg.length)
return arg
}
在這種情況下, 編譯器將不會(huì)知道 T 確實(shí)含有 length 屬性, 尤其是在可以將任何類型賦給類型變量 T 的情況下.我們需要做的就是讓類型變量 extends 一個(gè)含有我們所需屬性的接口, 比如這樣
interface Length {
length: number
}
function identity<T extends Length>(arg: T): T {
console.info(arg.length)
return arg
}
T extends Length 用于告訴編譯器, 我們支持已經(jīng)實(shí)現(xiàn) Length 接口的任何類型. 之后, 當(dāng)我們使用不含有 length 屬性的對(duì)象作為參數(shù)調(diào)用 identity 函數(shù)時(shí), TypeScript 會(huì)提示相關(guān)的錯(cuò)誤信息:
// identity(52)
// Argument of type 'number' is not assignable to parameter of type 'Length'.ts(2345)
此外, 我們還可以使用 , 號(hào)來(lái)分隔多種約束類型, 比如:<T extends Length, Type2, Type3>. 而對(duì)于上述的 length 屬性問(wèn)題來(lái)說(shuō), 如果我們顯式地將變量設(shè)置為數(shù)組類型, 也可以解決該問(wèn)題, 具體方式如下
function identity2<T>(arg: T[]): T[] {
console.info(arg.length)
return arg
}
identity2([1, 2, 3]) // function identity2<number>(arg: number[]): number[]
identity2([`1`, `2`, `3`]) // function identity2<string>(arg: string[]): string[]
// 或者
function identity3<T>(arg: Array<T>): Array<T> {
console.info(arg.length)
return arg
?? 4.2 檢查對(duì)象上的鍵是否存在
泛型約束的另一個(gè)常見(jiàn)的使用場(chǎng)景就是檢查對(duì)象上的鍵是否存在. 不過(guò)在看具體示例之前, 我們得來(lái)了解一下 keyof操作符,keyof操作符是在TypeScript 2.1版本引入的, 該操作符可以用于獲取某種類型的所有鍵, 其返回類型是聯(lián)合類型. 舉個(gè)keyof的使用示例:
interface Person {
name: string
age: number
location: string
}
type K1 = keyof Person // 'name' | 'age' | 'location'
type K2 = keyof Person[] // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person } // string | number
通過(guò) keyof操作符, 我們就可以獲取指定類型的所有鍵, 之后我們就可以結(jié)合前面介紹的extends約束,限制輸入屬性名包含在keyof返回的聯(lián)合類型中.
interface Person {
name: string
age: number
location: string
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const person: Person = {
name: 'su',
age: 22,
location: 'dalian',
}
// function getProperty<Person, "age">(obj: Person, key: "age"): number
console.info('getProperty(person, "age")', getProperty(person, 'age'))
// function getProperty<Person, "name">(obj: Person, key: "name"): string
console.info('getProperty(person, "name")', getProperty(person, 'name'))
在以上的 getProperty函數(shù)中, 我們通過(guò)K extends keyof T確保參數(shù)key一定是對(duì)象中含有的鍵, 這樣就不會(huì)發(fā)生運(yùn)行時(shí)錯(cuò)誤. 這是一個(gè)類型安全的解決方案, 與簡(jiǎn)單調(diào)用let value = obj[key]不同.
demo
enum Difficulty {
Easy,
Medium,
Hard,
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
let tsInfo = {
name: 'TypeScript',
supersetOf: 'JavaScript',
difficulty: Difficulty.Medium,
}
let difficulty: Difficulty = getProperty(tsInfo, 'difficulty') // OK
let name: string = getProperty(tsInfo, 'name') // OK
// let supersetof: string = getProperty(tsInfo, 'superset_of')
// ? Argument of type '"superset_of"' is not assignable to parameter of type '"difficulty" | "name" | "supersetOf"'.ts(2345)
很明顯通過(guò)使用泛型約束, 在編譯階段我們就可以提前發(fā)現(xiàn)錯(cuò)誤, 大大提高了程序的健壯性和穩(wěn)定性.
關(guān)注公眾號(hào)添加鬼哥微信,和鬼哥一起學(xué)習(xí)
?? 看完三件事
如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),不妨:
點(diǎn)個(gè)【在看】,或者分享轉(zhuǎn)發(fā),讓更多的人也能看到這篇內(nèi)容
點(diǎn)擊↓面關(guān)注我們,一起學(xué)前端
長(zhǎng)按↓面二維碼,添加鬼哥微信,一起學(xué)前端
評(píng)論
圖片
表情
