TypeScript(五)枚举、泛型

151 阅读4分钟

本文整理来自深入Vue3+TypeScript技术栈-coderwhy大神新课,只作为个人笔记记录使用,请大家多支持王红元老师。

枚举

枚举类型是为数不多的TypeScript特有的特性之一。枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型。枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型。

// 前面我们是这样定义方向的
// type Direction = "left" | "Right" | "Top" | "Bottom"

// 使用枚举,一般大写
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)

枚举的值

枚举类型默认是有值的,比如上面的枚举,默认值是这样的:

当然,我们也可以给枚举其他值,这个时候会从100进行递增:

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

认识泛型

软件工程的主要目的是构建不仅仅明确和一致的API,还要让你的代码具有很强的可重用性,比如我们可以通过函数来封装一些API,通过传入不同的函数参数,让函数帮助我们完成不同的操作,但是对于参数的类型是否也可以参数化呢?

什么是类型的参数化? 我们来提一个需求:封装一个函数,传入一个参数,并且返回这个参数。

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

上面的代码虽然实现了,但是不适用于其他类型,比如string、boolean、Person等类型,这时候你估计会想到使用any:

方法的参数中使用泛型

虽然any是可以的,但是定义为any的时候,我们其实已经丢失了类型信息。比如我们传入的是一个number,那么我们希望返回的可不是any类型,而是number类型,所以,我们需要在函数中可以捕获到参数的类型是number,并且同时使用它来作为返回值的类型。

所以我们需要泛型。

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

  1. 通过 <类型> 的方式将类型传递给函数,不常用

  1. 通过类型推导,自动推导出我们传入变量的类型。在这里会推导出它们是字面量类型的,因为字面量类型对于我们的函数也是适用的,这种方式更常用。

使用多个泛型

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

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

T:Type的缩写,类型
K、V:key和value的缩写,键值对
E:Element的缩写,元素
O:Object的缩写,对象

接口中使用泛型

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

当然我们也可以给泛型添加默认类型,添加默认泛型之后可以不传类型。

interface IPerson<T1 = string, T2 = number> {
  name: T1
  age: T2
}

// 这时候我们就不用传泛型
const p: IPerson = {
  name: "why",
  age: 18
}

类中使用泛型

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

// 回忆数组的写法
const names1: string[] = ["abc", "cba", "nba"]
const names2: Array<string> = ["abc", "cba", "nba"] // 不推荐(react jsx <>)

泛型约束

泛型约束就是泛型有一定的条件,不同的语言不一样,但是意思是一样的,比如Swift中的泛型约束是这样的:

// 要求传入的泛型,必须是Person类或者其子类并且遵守Runnable协议,如下:
protocol Runnable { }
class Person { }
func swapValues<T : Person & Runnable>(_ a: inout T, _ b: inout T) {
    (a, b) = (b, a)
}

有时候我们希望传入的类型有某些共性,但是这些共性可能不是在同一种类型中,比如string和array都是有length的,或者某些对象也是会有length属性的,那么只要是拥有length的属性都可以作为我们的参数类型,那么应该如何操作呢?在TS中,我们使用<T extends ILength>做泛型约束