最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Defining a Union Type from object values in Flow - Stack Overflow

programmeradmin4浏览0评论

I have an enum like this:

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

What I'd like to do is declare a union type like this:

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

However, this fails, but I'm not sure why. According to the Flow docs:

When you create an object with its properties, you create a sealed object type in Flow. These sealed objects will know all of the properties you declared them with and the types of their values.

So, if I'm reading that correctly, Flow should be able to create a type from those values. Instead, it fails with:

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

Here's a link to a Flow Try with a possible solution (that I'm not happy with) and other approaches that have unsuccessfully worked.

I have an enum like this:

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

What I'd like to do is declare a union type like this:

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

However, this fails, but I'm not sure why. According to the Flow docs:

When you create an object with its properties, you create a sealed object type in Flow. These sealed objects will know all of the properties you declared them with and the types of their values.

So, if I'm reading that correctly, Flow should be able to create a type from those values. Instead, it fails with:

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

Here's a link to a Flow Try with a possible solution (that I'm not happy with) and other approaches that have unsuccessfully worked.

Share Improve this question edited Jul 3, 2018 at 22:09 bbstilson asked Jul 3, 2018 at 21:57 bbstilsonbbstilson 1031 gold badge4 silver badges8 bronze badges 4
  • type FilterType = 'ALL' | 'COMPLETED' | 'UNCOMPLETED'...? I mean, if the constants are going to be named the same as their string values, there's no more hard-coding involved than there already is. You could also const Filter: { [K in FilterType]: K } = { ... } – Patrick Roberts Commented Jul 3, 2018 at 22:14
  • "there's no more hard-coding involved than there already is". There's the chance of typos; I'd prefer to just reference the enum itself. – bbstilson Commented Jul 3, 2018 at 22:25
  • You can't do that. As the error says, you're using a value as a type. Write your type first, and then implement your type with an object, or you don't even have to write an object at all, just use string literals. – Patrick Roberts Commented Jul 3, 2018 at 22:27
  • I hear what you're saying, but at the same time not having magic strings floating around is a better pattern. If I needed to change one of the values, I'd just change it in one spot instead of (in this case) two. All this said, I feel like the $Keys<typeof Filter> is the "right" way to do this in Flow. – bbstilson Commented Jul 3, 2018 at 22:32
Add a ment  | 

1 Answer 1

Reset to default 9

There's an easier solution. You can use $Values utility to get union of value types. And in order to make flow resolve types as literal types instead of just string the object should be frozen:

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 inpatible with enum FilterTypeA

Try

This pattern works since 0.60.0 version

发布评论

评论列表(0)

  1. 暂无评论