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

Add enum support #366

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

alecgibson
Copy link

@alecgibson alecgibson commented Sep 17, 2019

Fixes #67
Fixes #216

The enum is a popular aspect of TypeScript, and can be embedded in
interfaces as a concise, but descriptive, shorthand for literal string
unions:

enum Colour {
  White = '000000',
  Black = 'ffffff'
}

This change adds an exported member enum to io-ts, based on
this suggestion by @noe132

It means that enums can be reused directly in io-ts:

const T = t.enum(Colour)

@alecgibson
Copy link
Author

One place this does seem to fall down is that you lose the casting when extracting an interface. I can't quite figure out how to do that (possibly something to do with the encode function?). For example:

enum Colour {
  White = '000000'
}

const Style = t.type({
  colour: t.enum(Colour)
})

interface IStyle extends t.TypeOf<typeof Style> {}

const style: IStyle = {
  colour: Colour.White
}

const colour = style.colour // colour has type "any" rather than "Colour"

I tried tweaking the signature for enumType:

const enumType = <E, A = E[keyof E]>(e: E, name: string = 'Enum'): EnumType<A> => {
  const is = (u: unknown): u is A => Object.keys(e).some((k) => e[k as keyof E] === u)
  return new EnumType<A>(name, is, (u, c) => (is(u) ? success(u) : failure(u, c)), identity)
}

...which seems to only succeed in disallowing a decode to string (which I guess is correct?), but still doesn't correctly cast.

@jessmorecroft
Copy link

This looks like it might work better, for string enums at least...

const enumType = <E>(
  e: { [key: string]: E },
  name: string = 'Enum',
): EnumType<E> => {
  const is = (u: unknown): u is E => Object.keys(e).some(k => e[k] === u);
  return new EnumType<E>(
    name,
    is,
    (u, c) => (is(u) ? t.success(u) : t.failure(u, c)),
    t.identity,
  );
};

@saa18877433
Copy link

saa18877433 commented Feb 17, 2020 via email

@noe132
Copy link

noe132 commented Apr 18, 2020

Hey, since number enums have remapping,
https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings
I think it's essential to check if the key is the remapped one.

enum E {
  A = 1
}

// compiles to
const E {
  A: 1,
  '1': 'A',
}

In this case, 1 is valid, but 'A' is not.
https://www.typescriptlang.org/play?#code/KYOwrgtgBAolDeAoKUCCUC8UCMiC+QA

I've updated my code here #216 (comment)

@abrkn
Copy link

abrkn commented Aug 6, 2020

Any update on this?

@aroman
Copy link

aroman commented Jan 4, 2021

+1 this would be a great addition, as currently I need to manually copy/paste my enum values into a t.union of t.literals

@alecgibson alecgibson force-pushed the enum-support branch 3 times, most recently from c676682 to 9a34f36 Compare January 4, 2021 16:49
@alecgibson
Copy link
Author

Okay I've updated this, and it now correctly casts!

Screen Shot 2021-01-04 at 16 40 49

Also updated to include @noe132 's update for checking for reverse mapping

The `enum` is a popular aspect of TypeScript, and can be embedded in
interfaces as a concise, but descriptive, shorthand for literal string
unions:

```typescript
enum Colour {
  White = '000000',
  Black = 'ffffff'
}
```

This change adds an exported member `enum` to `io-ts`, based on
[this suggestion][1] by @noe132

It means that `enum`s can be reused directly in `io-ts`:

```typescript
const T = t.enum(Colour)
```

[1]: gcanti#216 (comment)
@Andrapyre
Copy link

Any update on this from @gcanti ?

@halbich
Copy link

halbich commented Dec 2, 2021

Hi, what is the current status of this feature? We'd love to have enum support :)

@taylor-shift
Copy link

@gcanti How do you feel about merging this in?

@martindines
Copy link

Is there anything stopping this feature from being merged?

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

Successfully merging this pull request may close these issues.

How to describe enums and still get typescript types? enum support
10 participants