ts泛型理解
1、初始泛型
过程:函数后的会先捕获传入的参数的类型,然后使用该类型传参,并要求返回同类型的值
点击查看代码
function returnItem<T>(params:T):T {
return params;
}
注意:T是一个特殊的变量,只表示类型,不作为值
2、多个类型参数
点击查看代码
// 多个类型参数
function returnItem2<T, U>(params:[T, U]):[T, U] {
return [params[0], params[1]]
}
console.log(returnItem2(['i', 2])); //['i', 2]
注意:
(1)多个类型参数时,传入、接收和返回的都应该是数组类型
(2)传入的参数里的元素类型可以是任意类型
3、泛型变量
点击查看代码
//告诉编译器我传入的参数时数组类型
function getArrayLength<T>(arg:Array<T>){
//数组里面的元素并不能确定,所以用any代替,可以更加灵活
console.log((arg as Array<any>).length);//5
return arg;
}
console.log(getArrayLength([1, 2, 3, 4, 5])); //[1, 2, 3, 4, 5]
注意:泛型在函数中使用时,函数名后是需要加泛型变量的用来捕获传入的参数类型
4、泛型接口
点击查看代码
//
interface ReturnItemFn<T> {
//函数的参数类型和返回值类型一致
(para: T): T
}
//传入一个number作为参数,并返回 number类型的值回来
const returnItem: ReturnItemFn<number> = para => para
注意:泛型在接口中使用时,接口名后是需要加泛型变量的用来捕获传入接口定义属性的类型
5、泛型类
点击查看代码
// 使用泛型类实现`栈`数据结构
class dealData<T> {
//泛型的数组,此处的泛型类型指的是数组内的元素的类型,可以是任意类型
private arr: Array<T> = [];
//此处传入的参数,也就是添加进数组的元素类型,上下文保持统一
public push(param: T) {
this.arr.push(param);
}
public pop() {
this.arr.pop();
}
public check() {
return this.arr;
}
}
const numberArr = new dealData();
numberArr.push(true);
console.log(numberArr.check()); //[true]
numberArr.pop();
console.log(numberArr.check()); //[]
注意:泛型在类中使用时,类名后是需要加泛型变量的用来捕获传入类所需的参数类型
6、泛型约束
点击查看代码
// 通过extends关键词继承string类型或number类型
//约束这个类只能传入这两种类型的参数
class dealData<T extends (string | number)> {
private arr: Array<T> = [];
public push(param: T) {
this.arr.push(param);
}
public pop() {
this.arr.pop();
}
public check() {
return this.arr;
}
}
//此时实列化为boolean类型就会报错
// const numberArr = new dealData<boolean>(); //error
//只能是string和number类型之一
const numberArr = new dealData<string | number>();
numberArr.push(1);
numberArr.push('2');
//进行泛型约束后,是不能传入约束条件之外的其他类型的,否则报错
// numberArr.push(true); // error
console.log(numberArr.check()); //[1, '2']
7、泛型约束与索引类型
需求:函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值
点击查看代码
// T extends object是因为这个object可以是很对种类型,像数组、元组、普通对象、枚举;T表示是其中一种类型
//U extends keyof T是表示U是T内的属性,可检测到的属性,属于联合类型
function getObjectValue<T extends object, U extends keyof T>(obj:T, key:U) {
return obj[key];
}
// 普通对象
let obj = {
id: 2,
name: 'zha'
};
console.log(getObjectValue(obj, "name")); //zha
// 数组
let arrNumObject:Array<number> = [1, 2, 3, 4];
console.log(getObjectValue(arrNumObject, 1)); // 2
// 元组
let object:[string, number] = ['d', 2];
console.log(getObjectValue(object, 0)); //d
// 枚举
enum arrObj { green = 2, red, blue };
console.log(getObjectValue(arrObj, 'red')); //3
8、使用多重类型进行泛型约束
点击查看代码
//规定只被两种接口类型约束
// 方式一:交叉类型
interface A{
AA():number
}
interface B{
BB(): string
}
//通过&关键符去链接合并A,B接口,直接合成类
class AB <T extends A & B>{
private default: T
use() {
this.default.AA();
this.default.BB();
}
}
// 方式二:超接口
//通过先合并接口,为一个子接口
interface Child extends A, B {
}
//子接口里面包含了AA,BB方法,所以可以直接被类继承
class ABC <T extends Child>{
private default: Child
use() {
this.default.AA();
this.default.BB();
}
}
注意:第一种代码更简洁
##### 9、泛型与 new
情况:如果传入的参数是构造函数的类型
点击查看代码
// 此处的new()指的是T的类型为构造函数类型
// 告诉编译器我传入的参数时个构造函数类型,这样函数里面才能使用new进行实例化
function Factory<T>(Type:{ new(): T }):T {
return new Type();
}
浙公网安备 33010602011771号