import * as t from 'io-ts';
import { withFallback} from 'io-ts-types';
const MyType = t.intersection([
withFallback(t.type({ prop1: t.string }), { prop1: 'a' }),
withFallback(t.type({ prop2: t.number }), { prop2: 1 }),
]);
MyType.decode(undefined); // throws: TypeError: Cannot read property 'prop1' of undefined
As both of the subtypes will return a value when decoding undefined, the intersection should also succeed (or fail without exception).
MyType.decode(undefined) to be equal to right({ prop1: 'a', prop2: 1 })
The mergeAll function used to merge all types in the validation of the interface should be able to handle an undefined input. And skip the u[k] !== base[k] check.
@mottetm,
If you replace
MyType.decode(undefined)
with
MyType.decode({})
Then no error is thrown, as {} successfully decodes into {prop1: 'a', prop2: 1}.
I think this is working as intended, and the issue you're running into here is that the use of t.type means MyType is looking for an object to decode, which undefined does not satisfy.
Potential solutions:
You can use a fallback value in your call to decode:
MyType.decode(undefined ?? {})
Or you could implement this fallback as a part of your codec with withFallback.
@EricCrosson, I would agree with you if
withFallback(t.type({ prop1: t.string }), { prop1: 'a' }).decode(undefined);
failed. However, this is not the case as it successfully returns right({ prop1: 'a' }). As far as I understand it decoding an intersection should work if all codecs in it succeed. The issue is that currently the intersection does an assumption about the input type.
I disagree that this is expected behaviour. The decode method types its foreign input as unknown, which suggests that you should be able to pass it anything. And, indeed, that's been my personal experience with the library. What's the point of a library that decodes foreign data if you have to refine it yourself first?
@mottetm thank you for the bug report, patch released.
@gcanti Thanks for all the awesome work! 馃檪