Skip to content

Commit e1771ff

Browse files
authored
feat: enum support (#5)
1 parent d64f2dd commit e1771ff

File tree

5 files changed

+94
-4
lines changed

5 files changed

+94
-4
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,28 @@ import { Decoder, array, field, number, string } from "json-decode";
138138
array(number)([1, 2, 3]); // [1, 2, 3]
139139
array(number)([1, 2, '3']); // throws a DecodeError
140140
```
141+
142+
### Decoding a TypeScript enum
143+
144+
```typescript
145+
import { enumerator } from "json-decode";
146+
147+
enum Choice {
148+
carrot = 'carrot',
149+
stick = 'stick'
150+
}
151+
152+
enumerator(Choice)('carrot'); // Choice.carrot
153+
enumerator(Choice)('stick'); // Choice.stick
154+
enumerator(Choice)('banana'); // throws a DecodeError
155+
156+
enum Fruits {
157+
apple,
158+
banana,
159+
pear,
160+
}
161+
162+
enumerator(Fruits)(0); // Fruits.apple
163+
enumerator(Fruits)(1) // Fruits.banana
164+
enumerator(Fruits)(3) // throws a DecodeError
165+
```

src/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ export function nullable<T>(decoder: Decoder<T>): Decoder<T | null>;
2525
export function optional<T>(decoder: Decoder<T>): Decoder<T | undefined>;
2626

2727
export const string: Decoder<string>;
28+
29+
export const enumerator: <T>(enumObject: T) => Decoder<T[keyof T]>;

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ export {
44
bool,
55
Decoder,
66
DecoderError,
7+
enumerator,
78
int,
89
field,
910
number,
1011
float,
1112
nullable,
1213
optional,
13-
string
14+
string,
1415
} from './lib/json-decode'

src/lib/json-decode.spec.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import {
44
bigint,
55
bool,
66
Decoder,
7-
DecoderError,
7+
DecoderError, enumerator,
88
field,
99
float,
1010
int,
1111
nullable,
1212
number,
1313
optional,
14-
string,
15-
} from './json-decode';
14+
string
15+
} from "./json-decode";
1616

1717
describe('bool', () => {
1818
it('decodes a boolean', () => {
@@ -125,6 +125,55 @@ describe('nullable', () => {
125125
});
126126
});
127127

128+
describe('enumerator', () => {
129+
130+
describe('when the enum is a string enum', () => {
131+
enum Choice {
132+
carrot = 'carrot',
133+
stick = 'stick'
134+
}
135+
136+
it('decodes the enum', () => {
137+
expect(enumerator(Choice)('carrot')).toEqual(Choice.carrot);
138+
});
139+
140+
it('throws when the value is not a member of the enum', () => {
141+
expect(() => enumerator(Choice)('banana')).toThrowError(DecoderError);
142+
});
143+
});
144+
145+
describe('when the enum is a numeric enum', () => {
146+
enum Choice {
147+
carrot = 0,
148+
stick = 1
149+
}
150+
151+
it('decodes the enum', () => {
152+
expect(enumerator(Choice)(0)).toEqual(Choice.carrot);
153+
});
154+
155+
it('throws when the value is not a member of the enum', () => {
156+
expect(() => enumerator(Choice)('banana')).toThrowError(DecoderError);
157+
});
158+
});
159+
160+
161+
describe('when the enum has no values assigned', () => {
162+
enum Choice {
163+
carrot ,
164+
stick
165+
}
166+
167+
it('decodes the enum using the value', () => {
168+
expect(enumerator(Choice)(1)).toEqual(Choice.stick);
169+
});
170+
171+
it('throws when the value is not a member of the enum', () => {
172+
expect(() => enumerator(Choice)(3)).toThrowError(DecoderError);
173+
});
174+
});
175+
})
176+
128177
describe('decoding a complex object', () => {
129178
type Blob = {
130179
name: string;

src/lib/json-decode.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,16 @@ export const nullable =
114114
<T>(decoder: Decoder<T>): Decoder<T | null> =>
115115
(json) =>
116116
json === null ? json : decoder(json);
117+
118+
export const enumerator = <T>(enumType: T) => (json: unknown): T[keyof T] => {
119+
const entries = Object.entries(enumType as any);
120+
const entry = entries.find(([, v]) => v === json);
121+
if (entry === undefined) {
122+
throw new DecoderError(`Expected enum value, got ${JSON.stringify(json)}`);
123+
}
124+
const value = entry[1];
125+
if (value === undefined) {
126+
throw new DecoderError(`Expected enum value, got ${JSON.stringify(json)}`);
127+
}
128+
return value as T[keyof T];
129+
}

0 commit comments

Comments
 (0)