天天看點

TypeScript——泛型泛型

泛型

TS中可以使用泛型建立可重用的元件,一個元件可以支援多種類型的資料,這樣使用者就可以以自己的資料類型來使用元件。

泛型變量

通過泛型變量,可以知道使用者傳入的類型,進而可以以這個類型作為函數的傳回類型。

function identity<T>(arg: T): T {
	return arg
}
           

當然也可以直接通過類型推斷

值得注意的是,對于泛型變量,它是可以代表任意類型的,如果不指定泛型變量的類型,就在函數中操作指定的類型變量所具有的方法,就會報錯。

例如:

function identity<T>(arg: T): T {
	console.log(arr.length)
	return arg  // 此時會報錯,T并沒有length這個屬性
}
           

解決方法

function identity<T>(arg: T[]): T[] {
	console.log(arr.length)// 此時就不會報錯,因為T[]可以代表任意資料類型的數組
	return arg
}
           

也可以這樣實作

function loggingIdentity<T>(arg: Array<T>): Array<T> {
	console.log(arg.length)
	return arg
}
           

此時這個泛型就代表任意資料類型的數組

泛型接口

  1. 常見的使用方式
interface GenericIdentityFn {
	<T>(arg: T): T
}

function identity<T>(arg: T): T {
	return arg
}

let myIdentity: GenericIdentityFn = identity
           

相當于

function identity<T>(arg: T): T {
	return arg
}

let myIdentity: {<T>(arg: T): T} = identity
           

即把 {(arg: T): T} 定義成一個接口使用

  1. 将泛型參數當作整個接口的一個參數使用
interface GenericIdentityFn<T> {
	(arg: T): T
}
function identity<T>(arg: T): T {
	return arg
}

let myIdentity: GenericIdentityFn<number> = identity
           

泛型類

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 }
           

需要注意的是,泛型類限制的隻是類的執行個體部分的類型,對于靜态部分不能使用泛型類。

泛型限制

泛型限制顧名思義在泛型的前提下加上一定的限制條件。

例如:

interface Lengthwise {
	length: number
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
	console.log(arg.length)
	return arg
}

loggingIdentity(3) // 報錯 3是number類型,并具有length這個屬性
loggingIdentity({length: 3, value: 3 }) // 不會報錯,因為傳入的變量具有length這個屬性
           
  1. 在泛型限制中使用類型參數
function getProperty(obj: T, key: K) {
	return obj[key]
}

let x = { a: 1, b: 2, c: 3, d: 4 }

getProperty(x, "a") // 成功
getProperty(x, "m") // 報錯  因為x這個對象上沒有m這個屬性
           

這段代碼就是通過類型限制,将Key規定為必須在obj上,即可以了解為這個對象上的屬性

  1. 在泛型裡使用類類型
class BeeKeeper {
	hasMask: boolean
}

class ZooKeeper {
	nametag: string
}

class Animal {
	numLegs: number
}

class Bee extends Animal {
	keeper: BeeKeeper
}

class Lio extends Animal {
	keeper: Zookeeper
}

function createInstance<A extends Animal>(c: new () => A): A {
	return new c()
}

createInstance(Lio).keeper.nametag
createInstance(Bee).keeper.hasMask