泛型
指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
背景
比如想实现一个函数接收数字或字符串类型参数,不用泛型可能会书写成👇🏻这样:
function print (a: number, b: number):Array<number> {
return [a, b]
}
print(1, 2)
function print2 (a: string, b: string):Array<string> {
return [a, b]
}
print2('1', '2')
单个类型参数
使用泛型后则使用函数名后的<T>
来指代任意输入的类型
function print3<T>(a: T, b: T): Array<T> {
return [a, b]
}
print3<number>(1, 2)
print3<string>('1', '2')
多个类型参数
function print4<T, U>(a: T, b: U): Array<T | U> {
let arr: Array<T | U> = [a, b]
return arr
}
print4(1, 2)
print4('1', 1)
泛型约束
下面栗子中访问 info 的 id 属性时,编译报错,因为不能证明 info 中有 id 属性
function getOluInfo<T>(info: T): T {
console.log(`ID: ${info.id}`); // Property 'id' does not exist on type 'T'.
return info;
}
如果需要限制函数处理带有 id 属性的类型,需要列出对于 T 的约束,可以定义一个接口用来描述约束条件,创建一个包含 id 属性的接口,利用 extends 关键字来实现
interface Info {
id: number;
}
function getOluInfo<T extends Info>(info: T): T {
console.log(`ID: ${info.id}`);
return info;
}
getOluInfo({ id: 2 });
getOluInfo("abc"); // Argument of type 'string' is not assignable to parameter of type 'Info'.
interface Len {
length: number
}
function print5<T extends Len>(a: T): T {
console.log(a.length)
return a
}
print5(3) // Argument of type 'number' is not assignable to parameter of type 'Len'.ts(2345)
keyof 约束
函数传入一个对象,根据形参 key 输出 value,传入一个不存在的 key,没有错误提示
function prop<T>(obj: T, key: string) {
return obj[key]
}
let obj = { a: 1, b: 2, c: 3 }
prop(obj, 'a')
prop(obj, 'd')
使用 keyof 约束后,得到错误提示
function prop<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
let obj = { a: 1, b: 2, c: 3 }
prop(obj, 'a')
prop(obj, 'd') // Argument of type '"d"' is not assignable to parameter of type '"a" | "b" | "c"'.ts(2345)
泛型类
类型参数在类名后面的尖括号中指定,可以具有泛型字段或方法
class Olu<T> {
hobby: T[] = []
say(a: T): T {
return a
}
}
const olu1 = new Olu<number>
olu1.hobby = [1, 2, 3]
olu1.say(233)
const olu2 = new Olu<string>
olu2.hobby = ['study', 'work', 'sleep']
olu2.say('hello')
泛型接口
interface Olu<T, U> {
id: T;
name: U;
}
const olu1:Olu<number, string> = {
id: 1,
name: 'olu1'
}
const olu2:Olu<string, string> = {
id: 2,
name: 'olu2'
}
函数类型的泛型接口
interface ShowOluName<T, U> {
(id: T, name: U): void;
}
const showOluName1: ShowOluName<number, string> = (id, name) => {
console.log(`id => ${id}, name => ${name}`);
};
showOluName1(1, "cute Olu!");
const showOluName2: ShowOluName<string, string> = (id, name) => {
console.log(`id => ${id}, name => ${name}`);
};
showOluName2("2", "cool Olu!");