使用泛型拯救你的 any
泛型简单来讲就是在不知道我需要什么类型的数据的时候,先用一个变量占据位置。
简单使用
const getArray = <T>(value: T, times: number = 5): T[] => {
return new Array(times).fill(value)
}
在定义函数前使用<>符号定义了一个泛型变量 T,这个 T 在这次函数定义中就表示一种类型,他可以是基础类型。也可以是联合类型或者高级类型.定义了泛型变量之后,你在函数中任何需要指定类型的地方使用 T 都代表这一类型.比如当我们传入 value 的类型为数值类型,那么返回的数组类型 T[]就表示 number[]类型
const getArray = <T>(value: T, times: number = 5): T[] => {
return new Array(times).fill(value);
};
getArray<number[]>([1,2],3).forEach(item=>console.log(item.length))
getArray<number>(2,3).forEach((item)=>{
console.log(item.length)
//errot 因为类型number上不存在length属性
})
第二个错误解读,我们传入了数字 2,可是我们函数里面定义的是返回一个数组里面是 T 类型的,而循环的时候 T 类型是数字,而数字没有 length
- 当然了我们也可以省略这个<number[]>,而 TypeScript 会依据我传入函数的 value 值进行推断
const getArray = <T>(value: T, times: number = 5): T[] => {
return new Array(times).fill(value)
}
getArray(2, 3).forEach(item => {
console.log(item.length)
}) //error 因为数字是没有length
泛型变量
我们可以把这个泛型数据当作任意类型来处理,意味着不是所有类型都做的操作不能做,不是所有类型都能调用的方法不能调用
const getLength = <T>(param: T): number => {
return param.length //error T上不存在length
}
当我们获取到一个类型为泛型的变量 param,时 要是 param 类型是数组或者字符串,那他具有 length 属性.但是如果传入的 param 是 number 类型则会报错.因为 T 不固定
const getArray = <T, U>(param1: T, param2: U, times: number): [T, U][] => {
return new Array(times).fill(param1, param2)
}
getArray(1, 'a', 3).forEach(item => {
console.log(item[0].length) //error类型number上不存在length
console.log(item[1].toFixed(2))
//error "toFixed"在类型"string"不存在
})
泛型函数类型
普通类型定义
//简单使用,不推荐
const getArray:<T>(arg:T,times:number):T[] = (arg,times)=>{return new Array(times).fill(arg)};
//使用类型别名
type GetArray=<T>(arg:T,times:number)=>T[];
const getArray:GetArray = <T>(arg:T,times:number):T[] =>{
return new Array(times).fill(arg)
}
我们也可以使用接口的形式来定义泛型函数
//定义了一个函数
interface GetArray(){
<T>(arg:T,times:number):T[];
}
//使用
const getArray:GetArray = <T>(arg:T,times:number):T[]=>{
return new Array(times).fill(arg)
}
- 还可以把接口提升到最外层,这样接口中所有属性和方法都能使用
interface GetArray<T> {
(arg: T, times: number): T[];
tag: T;
}
const getArray: GetArray<number> = <T>(arg: T, times: number): T[] => {
// error 不能将类型“{ <T>(arg: T, times: number): T[]; tag: string; }”分配给类型“GetArray<number>”。
// 属性“tag”的类型不兼容。
return new Array(times).fill(arg)
}
getArray.tag = 'a' // 不能将类型“"a"”分配给类型“number”
getArray('a', 1) // 不能将类型“"a"”分配给类型“number”
泛型约束
有的时候我们对泛型有约束,这个时候我们可以用 extends 继承来实现
interface ValueWitchLength {
length: number;
}
const v: ValueWitchLength = {}
//直接error因为缺少length属性
- 泛型约束
nterface ValueWithLength {
length: number;
}
const getLength = <T extends ValueWithLength>(param: T): number => {
return param.length;
};
getLength("abc"); // 3
getLength([1, 2, 3]); // 3
getLength({ length: 3 }); // 3
getLength(123); // error 类型“123”的参数不能赋给类型“ValueWithLength”的参数
在泛型中使用类型参数
const getProps = (object, propName) => {
return object[propName]
}
const obj = { a: 'aa', b: 'bb' }
getProps(obj, 'c') // undefined
- 使用类型参数的话
const getProp = <T, K extends keyof T>(object: T, propName: K) => {
return object[propName];
};
const obj = { a: "aa", b: "bb" };
getProp(obj, "c"); // 类型“"c"”的参数不能赋给类型“"a" | "b"”的参数
总结
- 泛型的概念与使用