Last updated on Oct 6, 2022

interface Res {
  code: number
  status: string
  data: any
}

对于这个接口结构,它描述了响应的消息结构,但如何这些类型标注更精确一些,达到 TypeScript 类型即文档的功能。

我们可以使用 联合类型 + 字面量类型 来达到这一目标

interface Res {
  code: 10000 | 10001 | 50000
  status: 'success' | 'failure'
  data: any
}

字面量类型(Literal Types)

字面量类型代表着比原始类型更精确的类型,同时也是原始类型的子类型

const str: 'Samuel' = 'Samuel'
const age: 25 = 25
const male: true = true

const bool1: true = true
const bool2: true = 'true' // X 不能将类型 "true" 分配给类型 'true'

枚举

在 JavaScript 中,类似 TypeScript 中的枚举这一概念的,大概是 constants 文件代码:

export const PageUrl = {
  HOME: process.env.HOME_PAGE_URL,
  ABOUT: process.env.ABOUT_PAGE_URL,
}

如果将这段代码替换为枚举

enum PageUrl {
  HOME = process.env.HOME_PAGE_URL,
  ABOUT = process.env.ABOUT_PAGE_URL,
}

const url = PagUrl.HOME

枚举值

如果没有声明枚举值,它会默认使用数字枚举值,并且从 0 开始逐渐递增:

// Items.Foo , Items.Bar , Items.Baz 的值依次是 0,1,2
enum Items {
  Foo, // 0
  Bar, // 1
  Baz, // 2
}

// 如果只为某一个成员指定了枚举值
// 那么之前未赋值成员仍然会使用从 0 递增的方式
// 之后的成员则会开始从枚举值递增
enum Items {
  Foo, // 0
  Bar = 599,
  Baz, // 600
}

// 在数字型枚举中,你可以使用延迟求值的枚举值
const returnNum = () => 100 + 499
enum Items {
  Foo = returnNum(),
  Bar = 599,
  Baz,
}
// 注意,延迟求值的枚举值是有条件的:
// 如果你使用了延迟求值,那么没有使用延迟求值的枚举成员必须放在使用常量枚举值声明的成员之后(如上例),或者放在第一位
enum Items {
  Baz,
  Foo = returnNum(),
  Bar = 599,
}
// 错误方式
enum Items {
  Foo = returnNum(),
  Baz, // X 枚举成员必须具有初始值设定项
  Bar = 599,
}

// 同时使用字符串枚举值和数字枚举值
enum Mixed {
  Num = 599,
  Str = 'linbudu',
}

枚举和对象的重要差异在于:对象是单向映射的,我们只能从键映射到键值;而枚举是双向映射的,即你可以从枚举成员映射到枚举值,也可以从枚举值映射到枚举成员:

enum Items {
  Foo,
  Bar,
  Baz,
}

const fooValue = Items.Foo // 0
const fooKey = Items[fooValue] // "Foo"
// 编译结果
"use strict";
var Items;
(function (Items) {
  Items[Items["Foo"] = 0] = "Foo";
  Items[Items["Bar"] = 1] = "Bar";
  Items[Items["Baz"] = 2] = "Baz";
})(Items || (Items = {}));
const fooValue = Items.Foo; // 0
const fooKey = Items[fooValue]; // "Foo"

obj[k] = v 的返回值即是 v。所以这里的 obj[obj[k] = v] = k 本质上就是进行了 obj[k] = v 与 obj[v] = k 这样两次赋值。