关于TypeScript中的泛型

242 阅读3分钟
终于完成了论文初稿,才有时间又可以更新自己的学习记录<开心>~

虽然项目开发中一直在使用TypeScript,但是对于泛型仅仅是“会使用”,没有过多的考虑过为什么使用泛型,也没有考虑过泛型给项目开发究竟带来了哪些好处?本文从项目开发经历中,简要总结一下泛型的相关知识,如有不妥,欢迎指正~

为什么使用泛型?

对于一个工具或者发明,我习惯性的思维方式是:为什么会产生这些工具或者发明?同样对于TypeScript,为什么要引入泛型的概念呢?

  • 提高可复用性
function returnInputNumberValue(input: number): number {
    return input;
}
function returnInputStringValue(input: string): string {
    return input;
}

以函数returnInputNumberValue和函数returnInputStringValue为例,在没有引入泛型之前,对于不同数据类型的参数要做不同的处理,或者有人会说我可以写成下面的形式:

function returnInputValue(input: number | string): number | string {
    return input;
}

的确在只有两种输入类型的时候,这样写是可以的,但是如果参数类型还有boolean、number[]、string[]、boolean[]等等,如果还用上面的形式,代码可读性就会大打折扣。有人会说,我直接给any类型不就可以了,那我会说你用any直接不用TypeScript就好了...有没有一种通用的方式,来表达这么冗长的类型判断呢?有:泛型

function returnInputValue<T>(input: T): T {
    return input;
}
//调用时可以随意传入需要的参数
const value1 = returnInputValue('1234'); // value1 === '1234'
const value2 = returnInputValue(12345); // value2 === 12345
const value3 = returnInputValue([1,2,3,4]); // value3 === [1,2,3,4]

使用泛型可以解决的问题?

  • 约束
// 创建
function printKey<T, K extends keyof T> (obj: T, key: K): void {
    console.log(K);
}

// 调用
const obj = {
    name: 'lily',
    age: 18
};
printKey(obj, 'name'); // 正确
printKey(obj, 'grade'); // 错误,约束第二个参数必须是第一个参数的key
  • 复用

除了上面提及的创建可复用的函数,还可以创建可复用的组件

class ReuseComponent<I, M> {
    name: I;
    age: M;
    constructor(name: I, age: M) {
        this.name = name;
        this.age = age;
    }
}
// 使用
const componentA = new ReuseComponent<string, number> ('lily', 18);
const componentB = new ReuseComponent<number, string> (99, 'flower');

如何使用泛型?

上文已经提及在函数中和类中使用泛型,下面再进行一些扩展和总结。

函数中使用泛型

假如一个函数需要实现的功能是:传入一个类,返回一个类的实例,这时候应该怎么定义呢?

function getInstance<C>(param: {new (): C}): C {
    return new param();
}

通过给函数传递一个类,函数内部自己会进行类的实例化并返回。

接口中使用泛型

真正项目开发中,也会用到一些可复用的接口。比如:

interface IFunction<T> {
    (param: T) => T;
}
function getValue<T>(arg: T): T {
    return arg;
}
let myFunc: IFunction<number> = getValue;
myFunc(12); // 12
类中使用泛型

下面看一个泛型使用相对本文其他例子来说较复杂的例子:

class Student {
    id: number;
}
class Lily extends Student {
    name: 'lily';
}
function createInstance<A extends Student>(param: new () => A): A {
    return new param();
}
createInstance(Lily).name; // 'lily'

总之,在项目开发中我们使用泛型无非就是为了提高可复用性、创建类型约束,具体如何使用还要根据项目背景出发~

以上就是工作中使用到的地方做的简要总结,持续学习持续更新中~