泛型基础
泛型解决什么问题?
- 含义: 把类型作为参数, 在调用时才确定;
- 收益: 逻辑只写一遍, 类型信息随调用点变化, 避免为每种类型重复实现或退化成
any; - 语法: 类型参数写在尖括号中, 如
<T>;
function createArray<T>(length: number, value: T): Array<T> {
const result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, "x"); // ["x", "x", "x"]; 显式指定类型参数
createArray(3, "x"); // 也可由实参推断出 T = string
箭头函数如何写泛型?
const createArray2 = <T>(length: number, value: T): Array<T> => {
const result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
};
- 位置: 类型参数写在参数列表之前;
- 边界:
.tsx中尖括号会被当作 JSX, 需要用<T,>或改用函数声明;
如何使用多个类型参数?
- 语法: 尖括号内用逗号分隔多个类型参数, 按位置依次绑定;
const swap = <T, U>(tuple: [T, U]): [U, T] => {
return [tuple[1], tuple[0]];
};
泛型参数的默认类型何时生效?
- 触发条件: 调用时既没有显式指定类型参数, 编译器也无法从实参推断;
- 语法:
<T = 默认类型>;
const createArray3 = <T = string>(length: number, value: T): Array<T> => {
const result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
};
为什么需要泛型约束?
- 问题: 泛型参数在函数内部仍是未知类型, 不能访问任何属性或方法;
- 目标: 在保持泛化的同时, 声明类型参数至少具备哪些成员;
如何用 extends 声明泛型约束?
interface Lengthwise {
length: number;
}
const loggingIdentity = <T extends Lengthwise>(arg: T): T => {
console.log(arg.length);
return arg;
};
- 语法:
<T extends 约束类型>; - 效果: 实参必须满足约束; 函数体内可以安全访问约束中声明的成员
length; - 返回值:
T仍是调用时的具体类型, 不会退化为约束类型;