遇到这个问题的是代码中存在一个魔法值,然后这个魔法值是 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
可以将 interface
的 key
自动转换为联合类型,也就是下面这样
type PeopleKeys = keyof People // 等同于 peoples = "name" | "age";
现在就是回到这个问题上,有很多人说 ts 在联合类型上完全能够替代枚举类型,但在魔法值的场景下,可能就是两种不同的情况,比如下面这样
// 枚举
let filterKey = PeopleKeys.NAME;
// 联合类型
let filterKey = "name" as PeopleKeys;
然后你们认为哪一种方式在魔法值场景下更加有效?
TypeScript 中参与计算的东西,可以简单的分为「类型」和「值」两大类。
所有「类型」都会在编译后消失(因为 JavaScript 没有类型)
所有「值」会保留,参与程序逻辑。
所以,理论上来说,从「类型」是计算不出来「值」的,但可以反过来从「值」计算出类型。
枚举在 TypeScript 中一种比较特殊的类型,它不仅是「类型」,也是「值」,转译出来会有一个 Object Literal。
那么,可以从枚举计算出来你所需要的 interface。如果所有属性都同一类型,比较好办
这样得到的
People
等同于interface People { name: string, age: string }
。但是,如果想按不同类型的属性来生成
People
,还需要写一个类型来建立 key 及其类型的关系……这不就是 interface 本身了么?所以,目前来看,如果需要 Key 的枚举,似乎还真就只有手写了。
如果只是加类型约束,倒是可以用
type PeopleKeys = keyof People
来约束,比如