io-ts-types
io-ts-types copied to clipboard
Unexpected behaviour when using `withFallback` with `t.union`
🐛 Bug report
Current Behavior
import * as tt from "io-ts-types";
import * as t from "io-ts";
import { pipe } from "fp-ts/function";
const Premium = t.type({
premium: tt.withFallback(t.literal(true), true),
});
const Free = t.type({
premium: tt.withFallback(t.literal(false), false),
});
const Union = t.union([Free, Premium]);
const z = {};
pipe(z, Free.decode, console.log);
// Right ✅
pipe(z, Union.decode, console.log);
// Left ❌
Expected behavior
See code comments above.
If Free.decode(z) returns a Right then I believe Union.decode(z) should also return a Right?
Reproducible example
Suggested solution(s)
Additional context
Your environment
package.json:
"fp-ts": "^2.12.2",
"io-ts": "^2.2.16",
"io-ts-types": "^0.5.16",
"monocle-ts": "^2.3.13",
"newtype-ts": "^0.3.5",
"typescript": "^4.7.4"
@OliverJAsh looks like io-ts detects Union as a tagged union (being "premium" the tag) and executes this path https://github.com/gcanti/io-ts/blob/63eea029773595b6a9cff9d70894935ae7a20e7e/src/index.ts#L1598 since {}['premium'] is undefined, so it returns early without giving withFallback a chance.
Not sure what's the possible fix, maybe execute a deoptimized validate instead of bailing out: https://github.com/gcanti/io-ts/compare/gcanti:63eea02...gcanti:11ecad3
WDYT?
That looks good to me but I'm not too familiar with the implementation. Maybe @mlegenhausen has some thoughts?
@gcanti this would be great. I think this should also cover possible other errors that could be introduced by custom types.