@@ -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
} ) ;
@@ -243,14 +243,53 @@ describe('object', () => {
243
243
} ) ;
244
244
} ) ;
245
245
246
- it ( 'ignores optional fields that decode to undefined' , ( ) => {
247
- const decoder = object ( {
248
- a : number ( ) ,
249
- b : optional ( string ( ) )
246
+ describe ( 'optional and undefined fields' , ( ) => {
247
+ it ( 'ignores optional fields that decode to undefined' , ( ) => {
248
+ interface AB {
249
+ a : number ;
250
+ b ?: string ;
251
+ }
252
+
253
+ const decoder : Decoder < AB > = object < AB > ( {
254
+ a : number ( ) ,
255
+ b : optional ( string ( ) )
256
+ } ) ;
257
+
258
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
259
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 } } ) ;
250
260
} ) ;
251
261
252
- expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
253
- expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 } } ) ;
262
+ it ( 'includes fields that are mapped to a value when not found' , ( ) => {
263
+ interface AB {
264
+ a : number ;
265
+ b : string ;
266
+ }
267
+
268
+ const decoder : Decoder < AB > = object < AB > ( {
269
+ a : number ( ) ,
270
+ b : oneOf ( string ( ) , constant ( undefined ) ) . map (
271
+ ( b : string | undefined ) => ( b === undefined ? 'b not found' : b )
272
+ )
273
+ } ) ;
274
+
275
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
276
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'b not found' } } ) ;
277
+ } ) ;
278
+
279
+ it ( 'includes fields that are mapped to a undefined when not found' , ( ) => {
280
+ interface AB {
281
+ a : number ;
282
+ b : string | undefined ;
283
+ }
284
+
285
+ const decoder : Decoder < AB > = object < AB > ( {
286
+ a : number ( ) ,
287
+ b : oneOf ( string ( ) , constant ( undefined ) )
288
+ } ) ;
289
+
290
+ expect ( decoder . run ( { a : 12 , b : 'hats' } ) ) . toEqual ( { ok : true , result : { a : 12 , b : 'hats' } } ) ;
291
+ expect ( decoder . run ( { a : 12 } ) ) . toEqual ( { ok : true , result : { a : 12 , b : undefined } } ) ;
292
+ } ) ;
254
293
} ) ;
255
294
} ) ;
256
295
@@ -334,32 +373,13 @@ describe('dict', () => {
334
373
} ) ;
335
374
336
375
describe ( 'optional' , ( ) => {
337
- describe ( 'decoding a non-object type' , ( ) => {
338
- const decoder = optional ( number ( ) ) ;
339
-
340
- it ( 'can decode the given type' , ( ) => {
341
- expect ( decoder . run ( 5 ) ) . toEqual ( { ok : true , result : 5 } ) ;
342
- } ) ;
343
-
344
- it ( 'can decode undefined' , ( ) => {
345
- expect ( decoder . run ( undefined ) ) . toEqual ( { ok : true , result : undefined } ) ;
346
- } ) ;
347
-
348
- it ( 'fails when the value is invalid' , ( ) => {
349
- expect ( decoder . run ( false ) ) . toMatchObject ( {
350
- ok : false ,
351
- error : { at : 'input' , message : 'expected a number, got a boolean' }
352
- } ) ;
353
- } ) ;
354
- } ) ;
355
-
356
376
describe ( 'decoding an interface with optional fields' , ( ) => {
357
377
interface User {
358
378
id : number ;
359
379
isDog ?: boolean ;
360
380
}
361
381
362
- const decoder : Decoder < User > = object ( {
382
+ const decoder = object < User > ( {
363
383
id : number ( ) ,
364
384
isDog : optional ( boolean ( ) )
365
385
} ) ;
@@ -449,8 +469,8 @@ describe('union', () => {
449
469
type C = A | B ;
450
470
451
471
const decoder : Decoder < C > = union (
452
- object ( { kind : constant < 'a' > ( 'a' ) , value : number ( ) } ) ,
453
- object ( { kind : constant < 'b' > ( 'b' ) , value : boolean ( ) } )
472
+ object < A > ( { kind : constant < 'a' > ( 'a' ) , value : number ( ) } ) ,
473
+ object < B > ( { kind : constant < 'b' > ( 'b' ) , value : boolean ( ) } )
454
474
) ;
455
475
456
476
it ( 'can decode a value that matches one of the union types' , ( ) => {
@@ -527,7 +547,7 @@ describe('valueAt', () => {
527
547
} ) ;
528
548
529
549
describe ( 'decode an optional field' , ( ) => {
530
- const decoder = valueAt ( [ 'a' , 'b' , 'c' ] , optional ( string ( ) ) ) ;
550
+ const decoder = valueAt ( [ 'a' , 'b' , 'c' ] , oneOf ( string ( ) , constant ( undefined ) ) ) ;
531
551
532
552
it ( 'fails when the path does not exist' , ( ) => {
533
553
const error = decoder . run ( { a : { x : 'cats' } } ) ;
@@ -628,7 +648,7 @@ describe('lazy', () => {
628
648
replies : Comment [ ] ;
629
649
}
630
650
631
- const decoder : Decoder < Comment > = object ( {
651
+ const decoder : Decoder < Comment > = object < Comment > ( {
632
652
msg : string ( ) ,
633
653
replies : lazy ( ( ) => array ( decoder ) )
634
654
} ) ;
0 commit comments