终于完成了论文初稿,才有时间又可以更新自己的学习记录<开心>~
虽然项目开发中一直在使用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'
总之,在项目开发中我们使用泛型无非就是为了提高可复用性、创建类型约束,具体如何使用还要根据项目背景出发~