泛型学习总结

118 阅读2分钟

前言

什么是泛型?看见别人写的泛型里的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不确定 image.png

那么现在要约束下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: '大海'});

image.png

泛型约束类

定义一个泛型类

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'};