TypeScript(十) 使用泛型拯救你的any

使用泛型拯救你的 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"”的参数

总结

  • 泛型的概念与使用

文章作者: 雾烟云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 雾烟云 !
  目录