通过代理设置常量

在这篇博客文章中,描述快速设置常量的小技巧(考虑枚举值,但不是包裹在命名空间里)。这是一个学习问题,而不是在你的代码中实际使用。

简单版

TypeScript 枚举

作为例子,考虑下面的 TypeScript 枚举(JavaScript 自身没有枚举):

enum MyEnum {
  foo,
  bar,
  baz,
}

assert.equal(MyEnum.foo, 0);
assert.equal(MyEnum.bar, 1);
assert.equal(MyEnum.baz, 2);

我通常优先使用字符串作为枚举值,因为它们更容易调试:

enum MyEnum {
  foo = 'foo',
  bar = 'bar',
  baz = 'baz',
}

assert.equal(MyEnum.foo, 'foo');
assert.equal(MyEnum.bar, 'bar');
assert.equal(MyEnum.baz, 'baz');

单纯的 JavaScript 解决方案

在 JavaScript 中你可以更少的代码做到相同的事:

const keyProxy = new Proxy(
  {},
  {
    get(_target, propKey, _receiver) {
      return propKey;
    },
  },
);
const { foo, bar, baz } = keyProxy;

assert.equal(foo, 'foo');
assert.equal(bar, 'bar');
assert.equal(baz, 'baz');

这是如何工作的?我们结合两个部分来了解这些。

首先,代理(proxy)是一个对象,无论你是用什么键读取属性,总是得到该键作为值:

assert.equal(keyProxy.hello, 'hello');
assert.equal(keyProxy.world, 'world');

再者,使用解构表达式获取属性值让我们同时获取属性键和变量名。意味着,下面两个解构是等价的。

const { foo, bar, baz } = keyProxy;
const { foo: foo, bar: bar, baz: baz } = keyProxy;

Symbol 作为常量的值

如果你使用 Symbol 作为常量的值,类型将更加安全。行 A 是唯一改变的一行。

const keyProxy = new Proxy(
  {},
  {
    get(_target, propKey, _receiver) {
      return Symbol(propKey); // (A)
    },
  },
);
const { foo, bar, baz } = keyProxy;

assert.equal(typeof foo, 'symbol');
assert.equal(String(foo), 'Symbol(foo)');

扩展阅读

英文原文:https://2ality.com/2018/08/enums-via-proxies.html

Copyright © 2019 by Wu WenJun