ts 魔法值场景下联合类型能否取代枚举类型?

遇到这个问题的是代码中存在一个魔法值,然后这个魔法值是 ts 一个 interface 的属性,比如下面这个

export interface People {
  name: string;
  age: number;
}
// ...
let filterKey = "name";

为了解决魔法值,我第一时间是想着去定义一个 const 变量或者枚举类型,比如下面这个

const PEOPLE_FILTER_KEY = "name";
// or
enum PeopleKeys = {
  NAME: "name";
  AGE: "age";
}

但我已经定义好了 People 这个 interface, 没道理还要再写一遍 enum 啊?就没有一种直接自动转换 key 为 enum 的吗?
后面找到 keyof 可以将 interfacekey 自动转换为联合类型,也就是下面这样

type PeopleKeys = keyof People // 等同于 peoples = "name" | "age";

现在就是回到这个问题上,有很多人说 ts 在联合类型上完全能够替代枚举类型,但在魔法值的场景下,可能就是两种不同的情况,比如下面这样

// 枚举
let filterKey = PeopleKeys.NAME;
// 联合类型
let filterKey = "name" as PeopleKeys;

然后你们认为哪一种方式在魔法值场景下更加有效?

阅读 3.7k
2 个回答

TypeScript 中参与计算的东西,可以简单的分为「类型」和「值」两大类。
所有「类型」都会在编译后消失(因为 JavaScript 没有类型)
所有「值」会保留,参与程序逻辑。

所以,理论上来说,从「类型」是计算不出来「值」的,但可以反过来从「值」计算出类型。

枚举在 TypeScript 中一种比较特殊的类型,它不仅是「类型」,也是「值」,转译出来会有一个 Object Literal。

那么,可以从枚举计算出来你所需要的 interface。如果所有属性都同一类型,比较好办

enum Keys {
    NAME = "name",
    AGE = "age",
}

type ValueOf<T> = {
    [key in keyof T]: T[key];
}

type People = Record<ValueOf<Keys>, string>;

这样得到的 People 等同于 interface People { name: string, age: string }

但是,如果想按不同类型的属性来生成 People,还需要写一个类型来建立 key 及其类型的关系……这不就是 interface 本身了么?

所以,目前来看,如果需要 Key 的枚举,似乎还真就只有手写了。

如果只是加类型约束,倒是可以用 type PeopleKeys = keyof People 来约束,比如

type PeopleKeys = keyof People;

function getPeopleProperty(people: People, key: PeopleKeys) {
    return people[key];
}

const james: People = { name: "James", age: 10 };

getPeopleProperty(james, "name");
getPeopleProperty(james, "otherkeys");  // Compile Error

不知道是不是你想要的感覺

但我在 enum 與 string 之間 想要同時都能使用時
是用這個方法來解決
https://github.com/bluelovers...

export type ITSToStringLiteralAllowedType = string | number | boolean | bigint;

export type ITSToStringLiteral<T extends ITSToStringLiteralAllowedType> = `${T}`

export type ITSTypeAndStringLiteral<T extends ITSToStringLiteralAllowedType> = T | ITSToStringLiteral<T>

將你的 enum PeopleKeys 丟入變成

let filterKey = "name" as ITSTypeAndStringLiteral<PeopleKeys>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题