Skip to content

Commit

Permalink
feat: enum support (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
leow93 authored Oct 11, 2023
1 parent d64f2dd commit e1771ff
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,28 @@ import { Decoder, array, field, number, string } from "json-decode";
array(number)([1, 2, 3]); // [1, 2, 3]
array(number)([1, 2, '3']); // throws a DecodeError
```

### Decoding a TypeScript enum

```typescript
import { enumerator } from "json-decode";

enum Choice {
carrot = 'carrot',
stick = 'stick'
}

enumerator(Choice)('carrot'); // Choice.carrot
enumerator(Choice)('stick'); // Choice.stick
enumerator(Choice)('banana'); // throws a DecodeError

enum Fruits {
apple,
banana,
pear,
}

enumerator(Fruits)(0); // Fruits.apple
enumerator(Fruits)(1) // Fruits.banana
enumerator(Fruits)(3) // throws a DecodeError
```
2 changes: 2 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export function nullable<T>(decoder: Decoder<T>): Decoder<T | null>;
export function optional<T>(decoder: Decoder<T>): Decoder<T | undefined>;

export const string: Decoder<string>;

export const enumerator: <T>(enumObject: T) => Decoder<T[keyof T]>;
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ export {
bool,
Decoder,
DecoderError,
enumerator,
int,
field,
number,
float,
nullable,
optional,
string
string,
} from './lib/json-decode'
55 changes: 52 additions & 3 deletions src/lib/json-decode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import {
bigint,
bool,
Decoder,
DecoderError,
DecoderError, enumerator,
field,
float,
int,
nullable,
number,
optional,
string,
} from './json-decode';
string
} from "./json-decode";

describe('bool', () => {
it('decodes a boolean', () => {
Expand Down Expand Up @@ -125,6 +125,55 @@ describe('nullable', () => {
});
});

describe('enumerator', () => {

describe('when the enum is a string enum', () => {
enum Choice {
carrot = 'carrot',
stick = 'stick'
}

it('decodes the enum', () => {
expect(enumerator(Choice)('carrot')).toEqual(Choice.carrot);
});

it('throws when the value is not a member of the enum', () => {
expect(() => enumerator(Choice)('banana')).toThrowError(DecoderError);
});
});

describe('when the enum is a numeric enum', () => {
enum Choice {
carrot = 0,
stick = 1
}

it('decodes the enum', () => {
expect(enumerator(Choice)(0)).toEqual(Choice.carrot);
});

it('throws when the value is not a member of the enum', () => {
expect(() => enumerator(Choice)('banana')).toThrowError(DecoderError);
});
});


describe('when the enum has no values assigned', () => {
enum Choice {
carrot ,
stick
}

it('decodes the enum using the value', () => {
expect(enumerator(Choice)(1)).toEqual(Choice.stick);
});

it('throws when the value is not a member of the enum', () => {
expect(() => enumerator(Choice)(3)).toThrowError(DecoderError);
});
});
})

describe('decoding a complex object', () => {
type Blob = {
name: string;
Expand Down
13 changes: 13 additions & 0 deletions src/lib/json-decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,16 @@ export const nullable =
<T>(decoder: Decoder<T>): Decoder<T | null> =>
(json) =>
json === null ? json : decoder(json);

export const enumerator = <T>(enumType: T) => (json: unknown): T[keyof T] => {
const entries = Object.entries(enumType as any);
const entry = entries.find(([, v]) => v === json);
if (entry === undefined) {
throw new DecoderError(`Expected enum value, got ${JSON.stringify(json)}`);
}
const value = entry[1];
if (value === undefined) {
throw new DecoderError(`Expected enum value, got ${JSON.stringify(json)}`);
}
return value as T[keyof T];
}

0 comments on commit e1771ff

Please sign in to comment.