前言
什么是泛型?看见别人写的泛型里的T,U这些都代表啥意思?
泛型:在你不确定数据类型的时候,就可以用泛型来写,其中的T,U这样的占位符可以理解成变量的参数
泛型的使用
首先我们来定义个函数
function onSayHello(arg: string) {
return arg;
}
这个函数里arg只能传字符串类型,如果我现在要传number类型我就要在加个类型
function onSayHello(arg: string | number) {
return arg;
}
如果arg类型不确定怎么办,可能你会想到用any,使用any是可以的,但是这就失去了使用ts类型校验的意义了
现在改成泛型就可以解决类型不确定的问题,这里的T你可以看成一个参数,<>里的就是我们要传入的参数,后面的arg:T 就是要用的这个T的参数,这样类型就统一了
function onSayHello<T>(arg: T): T {
return arg;
}
onSayHello('嗨');
onSayHello(123);
onSayHello({key: 'a'});
泛型多个变量
function getInfo<T, U>(value: T, message: U): T {
console.log(value,message)
return value;
}
console.log(getInfo<number, string>(30, '小明'));
这里的<T, U> 分别对应的参数value,message的类型
泛型约束
现在有这么个函数,我想要获取这个arg中的name属性,
function getName<T>(arg: T) {
console.log(arg.name)
return arg;
}
这个时候会报错,因为T不确定
那么现在要约束下T的类型,可以使用接口interface
interface NameInter {
name: string;
}
function getName<T extends NameInter>(arg: T) {
console.log(arg.name)
return arg;
}
T extends NameInter 就是约束了T的类型,入参中必须要name属性,没有就会报错
getName({name: '大海'});
泛型约束类
定义一个泛型类
class Game<T> {
time!: T;
getTime!: (x: T) => T;
}
然后声明一个numebr类型的实例,入参只能是number类型的参数
const game = new Game<number>();
game.time = 10;
game.getTime = (x) => {
return x + game.time;
};
console.log(game.getTime(30));
也可以定义string类型
const game = new Game<string>();
game.time = '10';
game.getTime = (x) => {
return x + game.time;
};
console.log(game.getTime('20'));
泛型约束接口
使用泛型来定义接口,让接口更灵活
interface KeyValueInter<T, U> {
key: T;
value: U;
}
const key1: KeyValueInter<string, number> = {key: 'key', value: 200};
const key2: KeyValueInter<number, string> = {key: 30, value: 'value'};