@@ -124,7 +124,7 @@ describe('constant', () => {
124124 interface TrueValue {
125125 x : true ;
126126 }
127- const decoder : Decoder < TrueValue > = object ( { x : constant ( true ) } ) ;
127+ const decoder : Decoder < TrueValue > = object < TrueValue > ( { x : constant ( true ) } ) ;
128128
129129 expect ( decoder . run ( { x : true } ) ) . toEqual ( { ok : true , result : { x : true } } ) ;
130130 } ) ;
@@ -133,7 +133,7 @@ describe('constant', () => {
133133 interface FalseValue {
134134 x : false ;
135135 }
136- const decoder : Decoder < FalseValue > = object ( { x : constant ( false ) } ) ;
136+ const decoder = object < FalseValue > ( { x : constant ( false ) } ) ;
137137
138138 expect ( decoder . run ( { x : false } ) ) . toEqual ( { ok : true , result : { x : false } } ) ;
139139 } ) ;
@@ -142,7 +142,7 @@ describe('constant', () => {
142142 interface NullValue {
143143 x : null ;
144144 }
145- const decoder : Decoder < NullValue > = object ( { x : constant ( null ) } ) ;
145+ const decoder = object < NullValue > ( { x : constant ( null ) } ) ;
146146
147147 expect ( decoder . run ( { x : null } ) ) . toEqual ( { ok : true , result : { x : null } } ) ;
148148 } ) ;
@@ -243,14 +243,53 @@ describe('object', () => {
243243 } ) ;
244244 } ) ;
245245
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 } } ) ;
250260 } ) ;
251261
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+ } ) ;
254293 } ) ;
255294} ) ;
256295
@@ -334,32 +373,13 @@ describe('dict', () => {
334373} ) ;
335374
336375describe ( '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-
356376 describe ( 'decoding an interface with optional fields' , ( ) => {
357377 interface User {
358378 id : number ;
359379 isDog ?: boolean ;
360380 }
361381
362- const decoder : Decoder < User > = object ( {
382+ const decoder = object < User > ( {
363383 id : number ( ) ,
364384 isDog : optional ( boolean ( ) )
365385 } ) ;
@@ -449,8 +469,8 @@ describe('union', () => {
449469 type C = A | B ;
450470
451471 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 ( ) } )
454474 ) ;
455475
456476 it ( 'can decode a value that matches one of the union types' , ( ) => {
@@ -527,7 +547,7 @@ describe('valueAt', () => {
527547 } ) ;
528548
529549 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 ) ) ) ;
531551
532552 it ( 'fails when the path does not exist' , ( ) => {
533553 const error = decoder . run ( { a : { x : 'cats' } } ) ;
@@ -628,7 +648,7 @@ describe('lazy', () => {
628648 replies : Comment [ ] ;
629649 }
630650
631- const decoder : Decoder < Comment > = object ( {
651+ const decoder : Decoder < Comment > = object < Comment > ( {
632652 msg : string ( ) ,
633653 replies : lazy ( ( ) => array ( decoder ) )
634654 } ) ;
0 commit comments