Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
2 of 10 tasks
ndbroadbent opened this issue Sep 15, 2020 · 1 comment
Open
2 of 10 tasks

Comments

@ndbroadbent
Copy link

ndbroadbent commented Sep 15, 2020

This is a:

  • Bug Report
  • Feature Request
  • Question
  • Other

Which concerns:

  • 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<typeof FIELD_TYPES>

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<typeof THING_TYPES>

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!

@jedwards1211
Copy link
Collaborator

Doesn't ThingType.unwrap() cause Flow errors? I'm just curious, I had always used (reify: Type<ThingType>), .unwrap() would be nice but I assume it couldn't possibly work with Flow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants