「TypeScript」入门进阶(四)✈️---泛型

764 阅读6分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

🎉 前言

  • 今天是七夕,先祝大家七夕快乐🎋🎋🎋
  • 虽然之前有学过TypeScript但是平时业务上面都还是用JavaScript来开发导致逐渐对TypeScript生疏了。
  • 借此更文活动的机会再来一起学习一下TypeScript的知识吧。
  • 在之前的文章中我们TypeScript的基础知识过了一遍,是不是发现其实也不会很难呢。
  • 本文也是TypeScript进阶篇的第四篇,讲的是泛型的那些事,关于基础篇可以看我之前分享的文章喔~
  • 本文大概1800+字,阅读可能需要八分钟~ 🥂

🍞 TypeScript泛型

  • 关于泛型,理解起来其实很简单,只要你盯着字看30s,你就会...不认识这个字!!
  • 好了开个玩笑,所谓泛型,在我看来顾名思义就是广泛的 类型,也就是说在我们定义一个函数或者是类和接口的时候,不先写死他的类型,而在真正使用它的时候在给它指定一种类型。

🥐 TypeScript数组泛型

  • 在理解泛型之前我们先了解一下数组泛型
  • 在我们之前分享的「TypeScript」入门基础(三)🎯中我们知道了数组在TypeScript是怎么定义的,当时我们用的是类型 + 方括号表示法,我们也可以使用数组泛型Array<elemType> 来表示数组。
  • 类型 + 方括号的写法
let fruit: string[] = ["apple", "banana", "mango"];
  • 数组泛型的写法
let fruit: Array<string> = ["apple", "banana", "mango"];
  • 这两种没什么不同单纯的只是写法不同而已,大家可以选择自己喜欢的方式表示数组。

🥖 关于泛型

  • 在我们编写代码的时候总会有复用函数的时候,在之前我们定义一个能返回stringnumber类型的函数的时候我们可以这样写。
function getOneGood(x:any):any{
  let id:any=x
  //一些操作
  return id
}
console.log(getOneGood('运动鞋')) //运动鞋
console.log(getOneGood(54188)) //54188
  • 如上例所示我们要获取一个商品的id的时候可能可以传商品名称或者商品编号来获取,在以前我们可能会这样写成AnyScript,这样虽然不会报错而且是没问题的,但是毕竟是不规范的,我们既然使用了TypeScript就要规范我们的类型,显而易见这样没有准确定义类型,这时候我们就可以使用泛型了。
function getOneGood<T>(x:T):T{
  let id:T=x
  return id
}
console.log(getOneGood<string>('运动鞋')) //运动鞋
console.log(getOneGood<number>(54188)) //54188
console.log(getOneGood<string>(54189)) //类型“number”的参数不能赋给类型“string”的参数
  • 如上例所示我们在这个函数后加一个<T>,这个T指的是我们可以任意指定一种类型,这样在后面的x:T:T中就可以使用这种类型了。
  • 我们给getOneGood指定了string则他的x值和返回值T就被确定是string了,下面的number也是一样的,如果我们给了不同类型的参数就会报错(如最后一行代码)。
  • 由此可见,我们不仅创建了一个可以复用的函数也规范了代码类型,这不是恰到好处吗~~
  • 值得一提的是,假设我们不给泛型函数指定类型那么它会自己推算成正确的类型。

image.png

🥯 泛型约束

  • 在上例中其实还有一种缺陷就是我们虽然可以在使用的时候指定类型,但是在函数运行的时候我们不可以随便执行这个变量的属性或者方法。
function getOneGood<T>(x:T):T{
  let id:T=x
  console.log(id.length) //类型“T”上不存在属性“lengthreturn id
}
  • 这样子写是会报错的,因为TypeScript不能保证你传进来的是有length属性的,所以到这它会卡住,那有没有办法可以保证他是有这个属性的呢?这时候我们的泛型约束就可以上场了。
interface haveLength {
  length: number;
}
function getOneGood<T extends haveLength>(x:T):T{
  let id:T=x
  console.log(id.length) //不报错
  return id
}
  • 如上例所示我们定义了一个接口haveLength这个接口的形状是有length属性的,那么我们T泛型用extends约束了这个接口,那么这个T必须包含length属性 image.png
  • 这时候在外部使用这个函数的时候变量如果没有length属性那么他就会报错。

🍖 泛型接口

  • 我们之前了解到可以用接口来制作一个规定的形状,当时是在定义接口的时候就规定好了类型,当然我们的接口也可以使用泛型,当我们使用接口的时候才规定类型。
interface Option<T> {
  value:T;
}
let agesOption:Option<string> = {
  value: '23' 
}
let ageOption:Option<number> = {
  value: 23
}
  • 如上例我们可以看到,我们制作这个接口的时候给了泛型,那么在使用它的时候就可以随意规定一个类型啦~~

🍟 泛型类

  • 当然类也是可以写成泛型的形式的。
class Goods<T>{//定义了一个名字为Goods的类
  id:T;
  constructor(id:T){//constructor是一个构造方法,用来接收参数
      this.id = id;
  };
}
let goodsName:Goods<string>=new Goods('运动鞋')
let goodsId:Goods<number>=new Goods(54188)
  • 如上例所示我们定义了一个名为Goods的类,里面接收一个参数id,我们定义的时候没有指定类型而是给了泛型。
  • 那我们在实例化这个类的时候就可以根据我们的需求来定制它的类型是什么了,不同的业务场景有不同的选择,这样以来也不会那么死板。

🍔 默认泛型类型

  • 我们在使用泛型的时候也可以给泛型一个默认的类型,这样当我们使用了用泛型定义的函数或接口和类时,即使我们没有给指定的类型也会有一种默认的类型存在。
class Goods<T=string>{//定义了一个名字为Goods的类
  id:T;
  constructor(id:T){//constructor是一个构造方法,用来接收参数
      this.id = id;
  };
}
let goodsName:Goods=new Goods('运动鞋')
let goodsId:Goods=new Goods(54188)//报错
  • 如上例所示我们给泛型设定了一个默认值,那么当我们在使用Goods类实例化的时候会默认选择参数为string类型,自然而然下面的代码会报错了。

image.png

👋 写在最后

  • 本文也算是记录一下TypeScript的学习,接下来我会持续输出TypeScript相关的知识,大家可以一起来学习。
  • 如果您觉得这篇文章有帮助到您的的话不妨🍉关注+点赞+收藏+评论+转发🍉支持一下哟~~😛

🌅 往期精彩

「TypeScript」入门基础(一)🎯---安装与基础数据类型

「TypeScript」入门基础(二)🎯---联合类型与接口

「TypeScript」入门基础(三)🎯---数组类型与函数类型

「TypeScript」入门基础(四)🎯---类型断言

「TypeScript」入门进阶(一)✈️---类型别名、字符串字面量与元组

「TypeScript」入门进阶(二)✈️--类

「TypeScript」入门进阶(三)✈️---类与接口