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

Custom errors #71

Open
johannes-lindgren opened this issue Oct 25, 2024 · 0 comments
Open

Custom errors #71

johannes-lindgren opened this issue Oct 25, 2024 · 0 comments
Labels
blocked proposal A feature request that hasn't been accepted

Comments

@johannes-lindgren
Copy link
Owner

johannes-lindgren commented Oct 25, 2024

#70 introduces a path in the error message which allows you to see where the parsing error occurred.

{
  tag: 'failure'
  error: 'not a number',
  path: [{
    tag: 'object',
    key: 'a',
  },{
    tag: 'array',
    index: 0,
  }],
}

Which means that data.a[0] failed to parse.

However, if the user adds their own parsers, they might also want to add their own custom errors that adhere to a different format. For example, they might want to include a different type of path segment that points to an index within a string:

{
  tag: 'string',
  index: number
}

However, as it stands, they're limited to tags object and array. According to this proposal, the path and error properties should be removed from the library and replaced by a new property error:

type ParseFailure<Error> = {
  tag: 'failure'
  error: Error
}

And:

type ParseResult<Value, Error> = ParseSuccess<Value> | ParseFailure<Error>

(The type parameter should be optional, so that you can write just Parse<?>.)

The higher order parsers should infer the types of the error messages, just as they infer the type parameter Value. So you could end up with a nested error that describes all possible failure outcomes; for example, for parsing an object with two properties a: number and b: string:

{
  tag: 'failure'
  error: {
    tag: 'object'
    errors: {
      tag: 'not-an-object',
    } | {
      tag: 'required-property-missing'
      key: 'a'
    } | {
      tag: 'property-failed'
      key: 'a',
      error: {
        tag: 'parseNumber-failure`
      }
    } | {
      tag: 'required-property-missing'
      key: 'b'
    } | {
      tag: 'property-failed'
      key: 'b',
      error: {
        tag: 'parseString-failure`
      }
    }
  }
}

Or maybe something more easy on the eye?

{
  tag: 'failure'
  error: {
    tag: 'not-an-object'
  } | {
    tag: 'property-failure'
    schema: {
      a: {
        tag: 'property-missing'
      } | {
        tag: 'parseNumber-failure'
      }
      b: {
        tag: 'property-missing'
      } | {
        tag: 'parseString-failure'
      }
    }
  }
}

We could provide function for converting this to a JSON path.

This would work when inferring types, but for explicit type declarations, this would become extremely unergonomic: since TypeScript does not implement partial type inference, the user would need to also specify the second type argument

Cons:

  • It will make the API more complicated, thus making it more complicated to extend; especially for higher order parsers. As a compromise, we could provide a default value as the second type parameter GeneralError which allows the user to bypass the complex error handling logic.
  • The size of the error grows with the size of the object.
  • Lots of work (but doable), but I don't know if anyone would use this feature.

Questions:

  • How are recursive types handled?
  • Will anyone ever be interested in the improved errors?
@johannes-lindgren johannes-lindgren added the proposal A feature request that hasn't been accepted label Oct 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked proposal A feature request that hasn't been accepted
Projects
None yet
Development

No branches or pull requests

1 participant