likes
comments
collection
share

TypeScript字面量类型及枚举类型

作者站长头像
站长
· 阅读数 2

本文主要介绍两种常用类型以及两种配置项,类型:字面量类型与联合类型、枚举类型;配置:isolatedModulespreserveConstEnums

类型

字面量类型与联合类型

为了增强 TypeScript 的类型系统,使其更能表达 JavaScript 中的精确类型信息。字面量类型允许我们明确地指定变量或参数的值必须是一个具体的常量值。

在以下情况下,我们可能需要用到字面量类型:

  1. 更精确的类型信息: 字面量类型允许你指定一个具体的值,而不仅仅是一个类型。例如,"male"2 不仅仅表示字符串或数字类型,而是表示确切的值。这使得类型信息更为具体和精确。
  2. 提高代码的可读性和可维护性: 使用字面量类型可以使代码更易读和易维护。通过明确地指定变量的可能值,你可以使代码更加自文档化,减少了对文档的依赖,也减少了潜在的错误。
  3. 更好的代码推断和类型推导: TypeScript 使用字面量类型能够更好地进行代码推断和类型推导。当你明确地指定一个值的类型时,TypeScript 可以更精确地推断和验证代码中的类型信息。
  4. 提供更强大的类型守卫: 字面量类型可以与联合类型、交叉类型等结合使用,提供更强大的类型守卫。这使得在编写条件分支和类型判断时更容易表达和理解。

考虑以下例子,展示了使用字面量类型的情况,Gender 类型使用了字面量类型,限定了可能的值为 "male""female"。这提供了明确的类型信息,使得代码更加可靠和易读:

type Gender = "male" | "female";

function getDisplayName(gender: Gender) {
  return gender === "male" ? "Mr." : "Ms.";
}

const userGender: Gender = "female";
const displayName = getDisplayName(userGender);

枚举

枚举是 TypeScript 中组织代码的一种有用方式。通过使用枚举,可以创建易于理解的常量,提高常量的可读性。枚举还允许开发人员在 JavaScript 中创建内存高效的自定义常量。

每当需要表示一组固定的常量时,都应该使用枚举类型。这包括像太阳系中的行星这样的枚举类型,以及在编译时已知所有可能值的数据集,比如菜单上的选项、命令行标志等。

以下是一个enum的定义实例:

enum Direction  {
  Up = 0,
  Down = 1,
  Left = 2,
  Right = 3
};

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

enum Direction  {
  Up,//0
  Down,//1
  Left,//2
  Right//3
};

如果只为某一个成员指定了枚举值,那么之前未赋值成员仍然会使用从 0 递增的方式,之后的成员则会开始从枚举值递增。

enum Direction  {
  Up,//0
  Down = 99,
  Left,//100
  Right//101
};

在数字型枚举中,你可以使用表达式或者函数计算数值:

const returnNum = () => 4;
enum Direction  {
  Up,//0
  Down = returnNum(),
  Left = 5,//5
  Right//6
};

但需要注意的是,表达式或者函数后面不能跟着没有声明值的枚举项,因为他没法根据前一个枚举项的值进行推导。

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

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
const directionValue = Direction.Up; // 0
const directionKey = Direction[0]; // "Up"

要了解这一现象的本质,我们需要来看一看枚举的编译产物,如以上的枚举会被编译为以下 JavaScript 代码:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
const directionValue = Direction.Up; // 0
const directionKey = Direction[0]; // "Up"

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

另外,还有一种比较特殊的枚举-常量枚举,相对于普通枚举,常量枚举在声明时多了一个const:

const enum Direction {
  Up,
  Down,
  Left,
  Right,
}

常量枚举只能通过枚举项访问值,另外在编译时会根据配置项preserveConstEnums的不同,进行不同的处理,详细的介绍请见下文关于preserveConstEnums的介绍。

TS config

isolatedModules

当我们不是使用TypeScript本身来转移TypeScript代码,而是使用第三方进行转译时(比如 Babel)。由于其他的转译器一次只处理一个文件,这意味着它们无法应用依赖于全类型系统理解的代码进行转换。

这些限制可能导致一些 TypeScript 功能在运行时出现问题,比如 const enums 和命名空间。设置 isolatedModules 标志告诉 TypeScript,在你编写了某些代码,这些代码无法通过单文件转译过程正确解释时,发出警告。

如下所示,类型A只存在于类型空间,由于第三方转译工具缺乏对全类型系统的理解,当我们在index.ts中尝试导出的时候,它不知道该导出成什么样的值,所以需要明确指出这是一个类型。

//moduleA.ts
export type A = string;
export function funcA() {}
//index.ts
import { A, funcA } from "./moduleA";

funcA();

export { A, funcA };
//ERROR-在启用了 `isolatedModules` 选项的情况下重新导出一个类型时,需要使用 `export type`

对于常量枚举的引用也是如此,单模块编译下,访问常量枚举成员时可能会导致类型上下文丢失,从而无法正确的解析出应有的常量值

declare const enum Numbers {
  Zero = 0,
  One = 1,
}
console.log(Numbers.Zero + Numbers.One);
//ERRO-在启用了 `isolatedModules`(孤立模块)选项的情况下,无法访问环境常量枚举。

preserveConstEnums

preserveConstEnums 用于控制是否保留(preserve)常量枚举的信息。常量枚举是 TypeScript 中的一种特殊枚举类型,其值在编译时被内联到使用它们的地方,而不会生成实际的 JavaScript 对象。

当设置 preserveConstEnumstrue 时,TypeScript 将保留常量枚举的信息,而不会在编译时将其完全内联。这意味着常量枚举在生成的 JavaScript 代码中会保留其原始结构,而不是被内联到每个使用它的地方。

如下所示:

const enum Album {
    JimmyEatWorldFutures = 1,
    TubRingZooHypothesis = 2,
    DogFashionDiscoAdultery = 3,
}

const selectedAlbum = Album.JimmyEatWorldFutures;
if (selectedAlbum === Album.JimmyEatWorldFutures) {
    console.log("That is a great choice.");
}

默认情况下(preserveConstEnumsfalse),常量枚举的行为是将任何 Album.Something 转换为相应的数字字面量,并完全从生成的 JavaScript 代码中删除对枚举的引用。

"use strict";

const selectedAlbum = 1 /* Album.JimmyEatWorldFutures */;
if (selectedAlbum === 1 /* Album.JimmyEatWorldFutures */) {
    console.log("That is a great choice.");
}

而当preserveConstEnums 设置为 true时,枚举在运行时仍然存在:

"use strict";

var Album;
(function (Album) {
    Album[Album["JimmyEatWorldFutures"] = 1] = "JimmyEatWorldFutures";
    Album[Album["TubRingZooHypothesis"] = 2] = "TubRingZooHypothesis";
    Album[Album["DogFashionDiscoAdultery"] = 3] = "DogFashionDiscoAdultery";
})(Album || (Album = {}));

const selectedAlbum = 1 /* Album.JimmyEatWorldFutures */;
if (selectedAlbum === 1 /* Album.JimmyEatWorldFutures */) {
    console.log("That is a great choice.");
}

以下是一些可能需要将其设置为 true 的情况:

  1. 与其他工具或库的兼容性: 有些工具或库可能依赖于在运行时保留常量枚举的结构。在这种情况下,启用 preserveConstEnums 可能有助于确保我们的代码与这些工具或库协同工作。
  2. 代码维护和调试: 如果在生成的 JavaScript 代码中保留了常量枚举的结构,可能会更容易进行调试和代码维护。这对于需要在生成的 JavaScript 代码中查看枚举值的情况可能很有用。

blog.logrocket.com/typescript-….