Skip to content

Commit f70f00c

Browse files
author
Elias Mulhall
committed
Allow constant decoder to match constant arrays and objects
Augment `constant` so that it can be used on any json data. This shouldn't impact performance for preexisting use cases for `constant`, but will perform a deep structural comparison for object and array decoders. Update documentation to show that string and number literal types inside of arrays and objects still require type annotations.
1 parent 5d376ff commit f70f00c

File tree

2 files changed

+37
-10
lines changed

2 files changed

+37
-10
lines changed

src/decoder.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as Result from './result';
2+
const isEqual = require('lodash/isEqual'); // this syntax avoids TS1192
23

34
/**
45
* Information describing how json data failed to match a decoder.
@@ -177,15 +178,19 @@ export class Decoder<A> {
177178
* and numbers, as detailed by this table:
178179
*
179180
* ```
180-
* | Decoder | Type |
181-
* | ---------------------------- | ----------------- |
182-
* | constant(true) | Decoder<true> |
183-
* | constant(false) | Decoder<false> |
184-
* | constant(null) | Decoder<null> |
185-
* | constant('alaska') | Decoder<string> |
186-
* | constant<'alaska'>('alaska') | Decoder<'alaska'> |
187-
* | constant(50) | Decoder<number> |
188-
* | constant<50>(50) | Decoder<50> |
181+
* | Decoder | Type |
182+
* | ---------------------------- | ---------------------|
183+
* | constant(true) | Decoder<true> |
184+
* | constant(false) | Decoder<false> |
185+
* | constant(null) | Decoder<null> |
186+
* | constant('alaska') | Decoder<string> |
187+
* | constant<'alaska'>('alaska') | Decoder<'alaska'> |
188+
* | constant(50) | Decoder<number> |
189+
* | constant<50>(50) | Decoder<50> |
190+
* | constant([1,2,3]) | Decoder<number[]> |
191+
* | constant<[1,2,3]>([1,2,3]) | Decoder<[1,2,3]> |
192+
* | constant({x: 't'}) | Decoder<{x: string}> |
193+
* | constant<{x: 't'}>({x: 't'}) | Decoder<{x: 't'}> |
189194
* ```
190195
*
191196
*
@@ -234,7 +239,7 @@ export class Decoder<A> {
234239
static constant(value: any): Decoder<any> {
235240
return new Decoder(
236241
(json: any) =>
237-
json === value
242+
isEqual(json, value)
238243
? Result.ok(value)
239244
: Result.err({message: `expected ${JSON.stringify(value)}, got ${JSON.stringify(json)}`})
240245
);

test/json-decode.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,28 @@ describe('constant', () => {
146146

147147
expect(decoder.run({x: null})).toEqual({ok: true, result: {x: null}});
148148
});
149+
150+
it('can decode a constant array', () => {
151+
type A = [1, 2, 3];
152+
const decoder: Decoder<A> = constant<A>([1, 2, 3]);
153+
154+
expect(decoder.run([1, 2, 3])).toEqual({ok: true, result: [1, 2, 3]});
155+
expect(decoder.run([1, 2, 3, 4])).toMatchObject({
156+
ok: false,
157+
error: {at: 'input', message: 'expected [1,2,3], got [1,2,3,4]'}
158+
});
159+
});
160+
161+
it('can decode a constant object', () => {
162+
type O = {a: true; b: 12};
163+
const decoder: Decoder<O> = constant<O>({a: true, b: 12});
164+
165+
expect(decoder.run({a: true, b: 12})).toEqual({ok: true, result: {a: true, b: 12}});
166+
expect(decoder.run({a: true, b: 7})).toMatchObject({
167+
ok: false,
168+
error: {at: 'input', message: 'expected {"a":true,"b":12}, got {"a":true,"b":7}'}
169+
});
170+
});
149171
});
150172

151173
describe('object', () => {

0 commit comments

Comments
 (0)