Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better validation errors for tagged unions #350

Open
anilanar opened this issue Jul 4, 2019 · 4 comments
Open

Better validation errors for tagged unions #350

anilanar opened this issue Jul 4, 2019 · 4 comments

Comments

@anilanar
Copy link

anilanar commented Jul 4, 2019

🚀 Feature request

Current Behavior

const C = t.union([
  t.type({
    type: t.literal('A'),
    foo: t.number,
  }),
  t.type({
    type: t.literal('B'),
    bar: t.number,
  }),
]);

// Validation errors have errors for A too
// e.g. 
// 0.type expected 'A', actual 'B'
// 0.foo expected number, actual undefined
// 1.bar expected number, actual 'wrong type'
C.decode({ type: 'B', bar: 'wrong type' }).value

Desired Behavior

It would be great if there was a way to reduce validation errors if there's a tag match. I have a tagged union of 10 codecs with dozens of properties and it is very hard to understand what is actually wrong.
So with above example codec, I'd expect the following validation error:

1.bar expected number, actual 'wrong type'
@gcanti
Copy link
Owner

gcanti commented Jul 4, 2019

I can't repro with io-ts@1.10.4 or io-ts@2.0.0

import * as t from 'io-ts'
import { PathReporter } from 'io-ts/lib/PathReporter'

const C = t.union([
  t.type({
    type: t.literal('A'),
    foo: t.number
  }),
  t.type({
    type: t.literal('B'),
    bar: t.number
  })
])

console.log(PathReporter.report(C.decode({ type: 'B', bar: 'wrong type' })))
// [ 'Invalid value "wrong type" supplied to : ({ type: "A", foo: number } | { type: "B", bar: number })/1: { type: "B", bar: number }/bar: number' ]

@anilanar
Copy link
Author

anilanar commented Jul 5, 2019

Oh I see, my bad.
I've checked the io-ts implementation now, union tag detection needs a TypeC or a StrictC and I was using some custom types.

@anilanar anilanar closed this as completed Jul 5, 2019
@anilanar
Copy link
Author

anilanar commented Jul 5, 2019

Alright, I'll reopen this so that this can be thought about. The only difference is mapOutput.

import * as t from 'io-ts'
import { mapOutput } from 'io-ts-types'
import { PathReporter } from 'io-ts/lib/PathReporter'

const C = t.union([
  mapOutput(t.type({
    type: t.literal('A'),
    foo: t.number
  }), x => x),
  t.type({
    type: t.literal('B'),
    bar: t.number
  })
])

console.log(PathReporter.report(C.decode({ type: 'B', bar: 'wrong type' })))

// 0: "Invalid value "B" supplied to : ({ type: "A", foo: number } | { type: "B", bar: number })/0: { type: "A", foo: number }/type: "A""
// 1: "Invalid value undefined supplied to : ({ type: "A", foo: number } | { type: "B", bar: number })/0: { type: "A", foo: number }/foo: number"
// 2: "Invalid value "wrong type" supplied to : ({ type: "A", foo: number } | { type: "B", bar: number })/1: { type: "B", bar: number }/bar: number"

@anilanar anilanar reopened this Jul 5, 2019
@klesun
Copy link

klesun commented Jul 1, 2021

In case someone would find it useful, I implemented a more aggressive union reduction reporter:

https://github.com/klesun/io-ts-better-union-error-reporter

The built-in PathReporter only seems to successfully eliminate unions on very basic types, but leaves the excessive options if there are sophisticated intersection types involved. The lib tries to solve that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants