• 【TypeScript】枚举类型和泛型的详细介绍


    TypeScript枚举类型

    枚举类型是为数不多的TypeScript特有的特性之一, JavaScript是没有的

    枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型

    枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型;

    枚举类型使用enum关键字定义, 建议枚举中定义的值使用大写

    枚举我们常见的使用方式如下

    enum Direction {
      LEFT,
      RIGHT,
      TOP,
      BOTTOM
    }
    
    function turnDirection(direction: Direction) {
      switch (direction) {
        case Direction.LEFT:
          console.log("转向左边")
          break;
        case Direction.RIGHT:
          console.log("转向右边")
          break;
        case Direction.TOP:
          console.log("转向上边")
          break;
        case Direction.BOTTOM:
          console.log("转向下边")
          break;
        default:
          const foo: never = direction
          break;
      }
    }
    
    // 测试
    turnDirection(Direction.LEFT)
    turnDirection(Direction.RIGHT)
    turnDirection(Direction.TOP)
    turnDirection(Direction.BOTTOM)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    枚举类型默认是有值的,比如上面代码的枚举,默认值其实是这样的

    enum Direction {
      LEFT = 0,
      RIGHT = 1,
      TOP = 2,
      BOTTOM = 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当然,我们也可以给枚举其他值, 比如我们给LEFT一个值: 100

    enum Direction {
      LEFT = 100,
      RIGHT,
      TOP,
      BOTTOM
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个时候LEFT后面的值如果没有设置值的话, 它们的默认值会从100进行递增, 相当于下面这样

    enum Direction {
      LEFT = 100,
      RIGHT = 101,
      TOP = 102,
      BOTTOM =103
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们也可以给他们赋值其他的类型

    enum Direction {
      LEFT,
      RIGHT,
      TOP = "TOP",
      BOTTOM = "BOTTOM"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    TypeScript泛型介绍

    🎲泛型的基本使用

    软件工程的主要目的是构建不仅仅明确和一致的API,还要让你的代码具有很强的可重用性

    比如我们可以通过函数来封装一些API,通过传入不同的函数参数,让函数帮助我们完成不同的操作;

    但是对于参数的类型是否也可以参数化呢?

    什么是类型的参数化?

    我们来提一个需求:封装一个函数,传入一个参数,并且返回这个参数;

    如果我们是TypeScript的思维方式,要考虑这个参数和返回值的类型需要一致

    // 传入number类型, 返回number类型
    function foo(arg: number): number {
      return arg
    }
    
    • 1
    • 2
    • 3
    • 4

    上面的代码虽然实现了,但是不适用于其他类型,比如string、 boolean、 Person等其他类型

    为了适用于其他类型, 我们可以定义为any类型

    // 传入number类型, 返回number类型
    function foo(arg: any): any {
      return arg
    }
    
    • 1
    • 2
    • 3
    • 4

    虽然any是可以的,但是定义为any的时候,我们其实已经丢失了类型信息

    比如我们传入的是一个number,那么返回的也是是any类型, 我们并不是希望它返回number类型,我们希望返回number类型;

    我们想要做到在函数中可以捕获到参数的类型是number,并且同时使用它来作为返回值的类型;

    我们需要在这里使用一种特性的变量 - 类型变量( type variable),它作用于类型,而不是值

    我们可以将它看做额外的一个参数;

    它可以做到, 在定义这个函数时, 不决定这些参数的类型, 而是让调用者以参数的形式告知, 这里的函数参数应该是什么类型

    function foo<Type>(arg: Type): Type {
      return arg
    }
    
    • 1
    • 2
    • 3

    这里我们可以使用两种方式来调用它

    • 方式一:通过 <类型> 的方式将类型传递给函数;
    foo<number>(123) // 传入number类型
    foo<{name: string}>({ name: "chenyq" }) // 传入有name属性的对象类型
    foo<number[]>([10, 20]) // 传入number类型的数组
    
    • 1
    • 2
    • 3
    • 方式二:通过类型推导,自动推导出我们传入变量的类型:

    在这里会推导出它们是字面量类型的,因为字面量类型对于我们这个函数也是适用的

    foo(50)
    foo("aaa")
    foo({ name: "kaisa" })
    
    • 1
    • 2
    • 3

    当然我们也可以传入多个类型

    function foo<T, E>(arg1: T, arg2: E) {
      console.log(arg1, arg2)
    }
    
    foo<number, string>(123, "abc")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    平时在开发中我们可能会看到一些常用的名称

    T: Type的缩写,类型

    K、 V: key和value的缩写,键值对

    E: Element的缩写,元素

    O: Object的缩写,对象


    🎲泛型接口的使用

    在定义接口的时候我们也可以使用泛型

    // 定义泛型接口
    interface IPerson<T1, T2> {
      name: T1
      age: T2
    }
    
    const p: IPerson<string, number> = {
      name: "chenyq",
      age: 18
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    泛型接口是没有类型推导的, 但是可以有默认值类型的

    // 泛型接口定义默认类型
    interface IPerson<T1 = string, T2 = number> {
      name: T1
      age: T2
    }
    
    const p: IPerson = {
      name: "chenyq",
      age: 123
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    🎲泛型类的使用

    我们也可以编写一个泛型类

    class Point<T> {
      x: T
      y: T
      z: T
    
      constructor(x: T, y: T, z: T) {
        this.x = x
        this.y = y
        this.z = z
      }
    }
    
    // 泛型类是可以自动推导类型的
    const p1 = new Point("1.22", "3.56", "7.32")
    // 也可以自己指定类型, 有下面两种方式
    const p2 = new Point<number>(10, 20, 30)
    const p3: Point<string> = new Point("1.22", "3.56", "7.32")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    🎲泛型的类型约束

    有时候我们希望传入的类型有某些共性,但是这些共性可能不是在同一种类型中

    比如string和array都是有length的,或者某些对象也是会有length属性的, 但是此时使用泛型, 编译阶段是会报错的, 因为不能保证泛型的所有类型都是有length属性的;

    在这里插入图片描述

    那么只要是拥有length的属性都可以作为我们的参数类型,而没有length属性的不允许作为参数, 那么应该如何操作呢?

    我们可以使用接口定义一个对象类型, 对象类型要求必须有length属性, 在让泛型继承自这个接口

    interface ILength {
      length: number
    }
    
    // 泛型继承自接口
    function getLength<T extends ILength>(arg: T) {
      console.log(arg.length)
    }
    
    // 测试
    // getLength(123) // 123没有length无法传入
    getLength("abc") // 3
    getLength([10, 20, 30]) // 3
    getLength({ length: 10 }) // 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    小谈设计模式(19)—备忘录模式
    MySQL基本操作大全
    工程伦理--16.1传统制造业的转型升级与伦理问题
    软件需求工程R 第十一、十二、十三章
    Qt 数据库的注册和登录功能
    1774. 最接近目标价格的甜点成本
    【面试八股总结】MySQL索引(二):B+树数据结构、索引使用场景、索引优化、索引失效
    【鸿蒙软件开发】ArkTS基础组件之Marquee(文字跑马灯)、QRCode(二维码生成)
    如果Controller里有私有的方法,能成功访问吗?
    【Python 实战基础】Pandas如何从股票数据找出收盘价最低行
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/126346250