【问题标题】:Defining a Union Type from object values in Flow根据 Flow 中的对象值定义联合类型
【发布时间】:2018-12-12 06:47:43
【问题描述】:

我有一个这样的枚举:

const Filter = {
  ALL: 'ALL',
  COMPLETED: 'COMPLETED',
  UNCOMPLETED: 'UNCOMPLETED'
};

我想做的是像这样声明一个联合类型:

type FilterType = Filter.ALL | Filter.COMPLETED | Filter.UNCOMPLETED

但是,这失败了,但我不确定为什么。根据Flow docs

当您创建一个具有其属性的对象时,您在 Flow 中创建了一个密封的对象类型。这些密封对象将知道您声明它们的所有属性及其值的类型。

所以,如果我没看错的话,Flow 应该能够从这些值创建一个类型。相反,它失败了:

Cannot use string as a type because string is a value. To get the type of a value use typeof.

这是一个指向 Flow Try 的链接,其中包含一个可能的解决方案(我不满意)和其他未成功的方法。

【问题讨论】:

  • type FilterType = 'ALL' | 'COMPLETED' | 'UNCOMPLETED'...?我的意思是,如果常量将被命名为与其字符串值相同的名称,那么就没有比现在更多的硬编码了。你也可以const Filter: { [K in FilterType]: K } = { ... }
  • “没有比现在更多的硬编码”。有错别字的机会;我宁愿只引用枚举本身。
  • 你不能那样做。正如错误所说,您使用 value 作为 type。先写你的类型,然后用一个对象实现你的类型,或者你根本不用写一个对象,用字符串字面量就行了。
  • 我听到你在说什么,但同时不让魔法弦四处飘荡是一种更好的模式。如果我需要更改其中一个值,我只需在一个位置更改它,而不是(在这种情况下)两个。综上所述,我觉得$Keys<typeof Filter> 是在 Flow 中执行此操作的“正确”方式。

标签: javascript reactjs flowtype


【解决方案1】:

有一个更简单的解决方案。您可以使用$Values 实用程序来获取值类型的联合。为了使流解析类型为文字类型,而不仅仅是string,对象应该被冻结:

const FilterA = Object.freeze({
  ALL: 'ALL',
  COMPLETED: 'COMPLETED',
  UNCOMPLETED: 'UNCOMPLETED'
});

type FilterTypeA = $Values<typeof FilterA>;


let a: FilterTypeA = FilterA.ALL; //OK
a = 'COMPLETED'; //OK

a = 'foo'; //$Expect error: string is incompatible with enum FilterTypeA

Try

这种模式从0.60.0 version开始有效

【讨论】:

  • 使用 Object.freeze 是否有任何类型影响,还是只是为了不变性?
  • @JamesKraus 只有不变性 - 在这种情况下,流可以确保属性类型无法更改。结果$Values&lt;typeof FilterA&gt; 将是'ALL' | 'COMPLETED' | 'UNCOMPLETED' 而不是string
  • 添加了源链接
猜你喜欢
  • 2021-10-19
  • 2019-06-05
  • 2021-12-02
  • 2019-06-19
  • 2017-05-02
  • 1970-01-01
  • 2020-03-04
  • 1970-01-01
  • 2022-07-08
相关资源
最近更新 更多