@@ -124,7 +124,7 @@ describe('constant', () => {
124
124
interface TrueValue {
125
125
x : true ;
126
126
}
127
- const decoder : Decoder < TrueValue > = object ( { x : constant ( true ) } ) ;
127
+ const decoder : Decoder < TrueValue > = object < TrueValue > ( { x : constant ( true ) } ) ;
128
128
129
129
expect ( decoder . run ( { x : true } ) ) . toEqual ( { ok : true , result : { x : true } } ) ;
130
130
} ) ;
@@ -133,7 +133,7 @@ describe('constant', () => {
133
133
interface FalseValue {
134
134
x : false ;
135
135
}
136
- const decoder : Decoder < FalseValue > = object ( { x : constant ( false ) } ) ;
136
+ const decoder = object < FalseValue > ( { x : constant ( false ) } ) ;
137
137
138
138
expect ( decoder . run ( { x : false } ) ) . toEqual ( { ok : true , result : { x : false } } ) ;
139
139
} ) ;
@@ -142,7 +142,7 @@ describe('constant', () => {
142
142
interface NullValue {
143
143
x : null ;
144
144
}
145
- const decoder : Decoder < NullValue > = object ( { x : constant ( null ) } ) ;
145
+ const decoder = object < NullValue > ( { x : constant ( null ) } ) ;
146
146
147
147
expect ( decoder . run ( { x : null } ) ) . toEqual ( { ok : true , result : { x : null } } ) ;
148
148
} ) ;
@@ -253,14 +253,53 @@ describe('object', () => {
253
253
} ) ;
254
254
} ) ;
255
255
256
- it ( 'ignores optional fields that decode to undefined' , ( ) => {
257
- const decoder = object ( {
258
- a : number ( ) ,
259
- b : optional ( string ( ) )
256
+ describe ( 'optional and undefined fields' , ( ) => {
257
+ it ( 'ignores optional fields that decode to undefined' , ( ) => {
258
+ interface AB {
259
+ a : number ;
260
+ b ?: string ;
261
+ }
262
+
263
+ const decoder : Decoder < AB > = object < AB > ( {
264
+ a : number ( ) ,
265
+ b : optional ( string ( ) )
266
+ } ) ;
267
+
268
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
269
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 } } ) ;
260
270
} ) ;
261
271
262
- expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
263
- expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 } } ) ;
272
+ it ( 'includes fields that are mapped to a value when not found' , ( ) => {
273
+ interface AB {
274
+ a : number ;
275
+ b : string ;
276
+ }
277
+
278
+ const decoder : Decoder < AB > = object < AB > ( {
279
+ a : number ( ) ,
280
+ b : oneOf ( string ( ) , constant ( undefined ) ) . map (
281
+ ( b : string | undefined ) => ( b === undefined ? 'b not found' : b )
282
+ )
283
+ } ) ;
284
+
285
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
286
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'b not found' } } ) ;
287
+ } ) ;
288
+
289
+ it ( 'includes fields that are mapped to a undefined when not found' , ( ) => {
290
+ interface AB {
291
+ a : number ;
292
+ b : string | undefined ;
293
+ }
294
+
295
+ const decoder : Decoder < AB > = object < AB > ( {
296
+ a : number ( ) ,
297
+ b : oneOf ( string ( ) , constant ( undefined ) )
298
+ } ) ;
299
+
300
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
301
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 , b : undefined } } ) ;
302
+ } ) ;
264
303
} ) ;
265
304
} ) ;
266
305
@@ -344,32 +383,13 @@ describe('dict', () => {
344
383
} ) ;
345
384
346
385
describe ( 'optional' , ( ) => {
347
- describe ( 'decoding a non-object type' , ( ) => {
348
- const decoder = optional ( number ( ) ) ;
349
-
350
- it ( 'can decode the given type' , ( ) => {
351
- expect ( decoder . run ( 5 ) ) . toEqual ( { ok : true , result : 5 } ) ;
352
- } ) ;
353
-
354
- it ( 'can decode undefined' , ( ) => {
355
- expect ( decoder . run ( undefined ) ) . toEqual ( { ok : true , result : undefined } ) ;
356
- } ) ;
357
-
358
- it ( 'fails when the value is invalid' , ( ) => {
359
- expect ( decoder . run ( false ) ) . toMatchObject ( {
360
- ok : false ,
361
- error : { at : 'input' , message : 'expected a number, got a boolean' }
362
- } ) ;
363
- } ) ;
364
- } ) ;
365
-
366
386
describe ( 'decoding an interface with optional fields' , ( ) => {
367
387
interface User {
368
388
id : number ;
369
389
isDog ?: boolean ;
370
390
}
371
391
372
- const decoder : Decoder < User > = object ( {
392
+ const decoder = object < User > ( {
373
393
id : number ( ) ,
374
394
isDog : optional ( boolean ( ) )
375
395
} ) ;
@@ -459,8 +479,8 @@ describe('union', () => {
459
479
type C = A | B ;
460
480
461
481
const decoder : Decoder < C > = union (
462
- object ( { kind : constant < 'a' > ( 'a' ) , value : number ( ) } ) ,
463
- object ( { kind : constant < 'b' > ( 'b' ) , value : boolean ( ) } )
482
+ object < A > ( { kind : constant < 'a' > ( 'a' ) , value : number ( ) } ) ,
483
+ object < B > ( { kind : constant < 'b' > ( 'b' ) , value : boolean ( ) } )
464
484
) ;
465
485
466
486
it ( 'can decode a value that matches one of the union types' , ( ) => {
@@ -537,7 +557,7 @@ describe('valueAt', () => {
537
557
} ) ;
538
558
539
559
describe ( 'decode an optional field' , ( ) => {
540
- const decoder = valueAt ( [ 'a' , 'b' , 'c' ] , optional ( string ( ) ) ) ;
560
+ const decoder = valueAt ( [ 'a' , 'b' , 'c' ] , oneOf ( string ( ) , constant ( undefined ) ) ) ;
541
561
542
562
it ( 'fails when the path does not exist' , ( ) => {
543
563
const error = decoder . run ( { a : { x : 'cats' } } ) ;
@@ -638,7 +658,7 @@ describe('lazy', () => {
638
658
replies : Comment [ ] ;
639
659
}
640
660
641
- const decoder : Decoder < Comment > = object ( {
661
+ const decoder : Decoder < Comment > = object < Comment > ( {
642
662
msg : string ( ) ,
643
663
replies : lazy ( ( ) => array ( decoder ) )
644
664
} ) ;
0 commit comments