gajus / gajus/flow-runtime

Problem with Literal Types extracted from an object using $Values<typeof OBJECT>

Open
#252 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
797
Forks
49
PR merge metrics
No merged PRs in 30d

Description

This is a:

- [X] Bug Report
- [ ] Feature Request
- [ ] Question
- [ ] Other

Which concerns:

- [X] flow-runtime
- [ ] babel-plugin-flow-runtime
- [ ] flow-runtime-validators
- [ ] flow-runtime-mobx
- [ ] flow-config-parser
- [ ] The documentation website

---

### Background

I have been using an "enum" pattern with Flow that makes it a little easier to work with types.

First, I define some constants where they have a Literal Type for a specific string. Then I use these constants to build an object with some accessor keys. Finally, I use `$Values` to grab the types of each value and build a string enum for the type. Here's a real example from my application:

```
export const FIELD_TYPE_STRING: 'string' = 'string'
export const FIELD_TYPE_NUMBER: 'number' = 'number'
export const FIELD_TYPE_BOOLEAN: 'boolean' = 'boolean'
// ...

export const FIELD_TYPES = {
STRING: FIELD_TYPE_STRING,
NUMBER: FIELD_TYPE_NUMBER,
BOOLEAN: FIELD_TYPE_BOOLEAN,
// ...
}
export type FieldType = $Values
```

Then I can write code like this:

```
const type: FieldType = FIELD_TYPES.STRING
```

I can confirm that this pattern works fine with vanilla Flow, and Flow will raise an error if I try to assign `"foo"` to a variable with the `FieldType` type.

However, it looks like `flow-runtime` is struggling with these literal types, and it turns everything into `string | string | string | ...`

I am trying to see if I can use `flow-runtime` to automatically extract some of these enums and use them in other parts of my application (in a different programming language.)

### What is the current behaviour?

Code (for https://gajus.github.io/flow-runtime/#/try)

```
import t, { reify } from 'flow-runtime'
import type { Type } from 'flow-runtime'

export const THING_TYPE_ONE: 'one' = 'one'
export const THING_TYPE_TWO: 'two' = 'two'
export const THING_TYPE_THREE: 'three' = 'three'

export const THING_TYPES = {
ONE: THING_TYPE_ONE,
TWO: THING_TYPE_TWO,
THREE: THING_TYPE_THREE,
}
type ThingType = $Values

type Thing = {
id: string | number;
name: string;
thing: ThingType;
};

const widget: Thing = {
id: 123,
name: 'Widget',
thing: 'unknown'
};
console.log(widget);
console.log(ThingType.unwrap().toString())

```

Output:

```
{
id: 123,
name: "Widget",
thing: "unknown"
}
string | string | string
```
---

### What is the expected behaviour?

I am expecting the `widget` declaration to fail with an error like this:

```
Thing.thing must be one of: "one" | "two" | "three"

Expected: "one" | "two" | "three"

Actual Value: "unknown"

Actual Type: string
```

I am also expecting `ThingType.unwrap().toString()` to return `"one" | "two" | "three"`.

### Workaround

In the meantime, I could change my code and manually define the string enum:

```
export const FIELD_TYPE_STRING: 'string' = 'string'
export const FIELD_TYPE_NUMBER: 'number' = 'number'
export const FIELD_TYPE_BOOLEAN: 'boolean' = 'boolean'
// ...

export const FIELD_TYPES = {
STRING: FIELD_TYPE_STRING,
NUMBER: FIELD_TYPE_NUMBER,
BOOLEAN: FIELD_TYPE_BOOLEAN,
// ...
}
export type FieldType = 'string' | 'number' | 'boolean' | ...
```

But I would love to avoid the duplication and be able to use `$Values` to extract these Literal Types.

### Which package versions are you using?

Latest versions on https://gajus.github.io/flow-runtime/#/try

Thank you!

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.