通用
指在定义函数、接口或类时不预先指定具体类型,而是在使用时指定具体类型的特性。
介绍
在下面创建一个函数来实现该功能:根据指定的数字计数和数据值,创建一个包含计数值的数组。如果没有泛型,这个函数可能如下:
function createArray(value: any, count: number): any[] {
const arr: any[] = []
for (let index=0; index < count; index++) {
arr.push(value)
}
return arr
}
const arr1 = createArray('a', 3)
const arr2 = createArray(1, 3)
console.log(arr1)
console.log(arr2)
console.log(arr1[0].toFixed(), arr2[0].split(''))
我们创建了一个函数createArray,传入了2个参数value和count,返回了一个any类型的数组,然后定义了一个any类型的空数组arr。接下来我们看看结果
我们在编译阶段没有报错,因为我们将值设置为任意类型,但是编译完成运行时,arr1是一个字符串,并且该字符串没有toFixed方法,所以会报错如果报错,那么我们希望编译阶段如果报错,可以使用泛型
使用泛型
// 使用函数泛型
function createArray(value: T, count: number): T[] {
const arr: Array = []
for (let index=0; index < count; index++) {
arr.push(value)
}
return arr
}
const arr1 = createArray(11, 3)
console.log(arr1[0].toFixed())
const arr2 = createArray('AA', 3)
console.log(arr2[0].split(''))
console.log('---------')
console.log(arr2[0].toFixed()) // 报错,因为字符串没有toFixed方法
console.log(arr1[0].split('')) // 报错,因为number没有split方法
泛型表示类型由用户决定,如函数createArray(value: T, count: number): T[],函数createArray和value参数及返回类型由用户决定。
const arr1 = createArray(11, 3)这段代码是没有问题的,因为指定了数字类型,并且也传入了数字
当我们将代码修改为如下代码时:
我们发现报错,因为指定了数字类型,但是传入的是字符串11,
当我们输入以下代码时,也会报错
报错原因如下
所以如果我们使用泛型,我们可以避免输入错误或使用错误的方法
具有多个泛型参数的函数
一个函数可以定义多个泛型参数
function swap (a: K, b: V): [K, V] {
return [a, b]
}
const result = swap('abc', 123)
console.log(result[0].length, result[1].toFixed())
通用接口
interface IbaseCRUD {
// 定义泛型数组data
data: T[]
add: (t: T) => void
getById: (id: number) => T
}
class User {
id?: number;
name: string;
age: number;
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class UserCRUD implements IbaseCRUD {
data: User[] = []
add(user: User): void {
user = {...user, id: Date.now()}
this.data.push(user)
console.log('保存user', user.id)
}
getById(id: number): User {
return this.data.find(item => item.id === id)
}
}
const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
通用类
泛型类看起来类似于泛型接口。泛型类使用 ( ) 将泛型类型括起来,跟在类名之后。
class GenericNumber {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
GenericNumber 类的使用非常直观,您可能已经注意到,没有什么将它限制为数字类型。也可以使用字符串或其他更复杂的类型。
let stringNumeric = new GenericNumber();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));
与接口一样,将泛型类型直接放在类之后可以帮助我们确保类的所有属性都使用相同的类型。
通用约束
如果我们直接取泛型参数的length属性,会报错,因为泛型根本不知道自己有这个属性
// 没有泛型约束
function fn (x: T): void {
console.log(x.length) // 报错,因为目前不知道x是什么类型
}
我们可以使用通用约束来实现这一点
interface Lengthwise {
length: number;
}
// 指定泛型约束
function fn2 (x: T): void {
console.log(x.length)
}
我们需要传入一个符合约束类型的值,该值必须包含所需的长度属性:
fn2('abc')
// fn2(123) // error number没有length属性
暂无评论内容