这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
什么是泛型?
我想设计一个函数,参数为 number 类型,返回值也为 number 类型,TS 可以约束参数和返回值类型,这里你将参数和返回值类型都设置为 number 就可以了。
如果我预先不知道这个函数输入的类型是什么,只是希望不管这个函数传入的参数类型是什么,返回值类型都能和参数类型保持一致,这样能实现吗?
这个可以使用泛型来解决呀。
那我赶紧学习一下,泛型相关的知识吧。
泛型函数
泛型是 TS 中非常重要的概念,它极大的增强 TS 的类型表达能力。下面我们先来学习泛型在函数中,是如何使用的。
我们先来看看没有加泛型的函数 createArray,它接收两个参数,分别是值和数组的长度,然后在里面会创建一个新的数组,根据数组的长度,填充传入的值,这样的话,就可以返回一个每一项都是这个值的数组,比如,下面的输出结果。
function createArray(value, length) {
let arr = [];
for (let i = 0; i < length; i++) {
arr[i] = value;
}
return arr;
}
let fooArray = createArray('foo', 3);
console.log(fooArray);
// ['foo', 'foo', 'foo']
下面我们给这个函数添加上类型,由于它的输入 value,是可以接收为任何类型的,所以它是 any 类型,length 是 number 类型,那它的返回值应该是每一项都是 any 类型的数组,但是这样做会有什么问题呢?
function createArray(value: any, length: number): any[] {
let arr = [];
for (let i = 0; i < length; i++) {
arr[i] = value;
}
return arr;
}
let fooArray = createArray('foo', 3);
console.log(fooArray);
// ['foo', 'foo', 'foo']
可以看到 fooArray 是每一项都为 any 类型的数组,那么我们在取用它的某一项的时候,就无法预知它会有什么属性或者方法。但是其实,我们这个时候传入的是 string 类型。怎么办呢?
我们可以添加上泛型,使用尖括号的格式,然后将所有 any 类型都替换成 T,然后再调用函数的时候,也是使用尖括号的形式,传入一个 string 类型。
改造后:
function createArray<T>(value: T, length: number): T[] {
let arr = [];
for (let i = 0; i < length; i++) {
arr[i] = value;
}
return arr;
}
let fooArray = createArray<string>('foo', 3);
console.log(fooArray);
// ['foo', 'foo', 'foo']
通过上面操作,我们可以看到 createArray 函数的输入是 string,返回是 string 类型的数组。
可以看到它的每一项都变成了 string 类型,并且有了 string 的属性和方法。
使用泛型的优势,就在于我们可以动态调整这个类型,比如说,传入的是数字的话,我们可以修改成下面这样,这样的话,它就变成每一项为 number 类型的数组了。
let fooArray = createArray<number>(1, 3);
习题:求函数 animalInfo
的返回值类型
const animalInfo = <T>(arg: T) _____ => {
return {
age: arg,
name: 'panda'
};
};
animalInfo<string>('10');
animalInfo<number>(10);
// A
{
age: string;
name: string;
}
// B
{
age: number;
name: string;
}
// C
{
age: T;
name: string;
}
// D
{
age: any;
name: string;
}
答案:
C
解析:
函数 animalInfo
的返回值为
{
age: arg,
name: 'panda'
}
所以只需要确定变量 arg
的类型即可。arg
参数中已经确定了泛型 T
。所以答案选 C
。
资料:泛型的命名
泛型是一种很自由的类型,我们一般用 T
来表示泛型,但这不是必须的。
我们可以根据自身业务或者需求来约定好泛型的命名规则,例如 Google 团队在 Google Java Style Guide 中就推荐了两种命名方式:
Each type variable is named in one of two styles:
- A single capital letter, optionally followed by a single numeral (such as E, T, X, T2)
- A name in the form used for classes (see Section 5.2.2, Class names), followed by the capital letter T (examples: RequestT, FooBarT).
附:常用单字母泛型命名规则
字母 | 类型 | 场景 |
---|---|---|
E | 元素 | |
K | 键 | |
V | 值 | |
N | 数字 | |
T | 类型 | 主要用于表示第一个参数 |
S | 类型 | 主要用于表示第二个参数 |
U | 类型 | 主要用于表示第三个参数 |
V | 类型 | 主要用于表示第四个参数 |