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

Typed error #634

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft

Conversation

kamijin-fanta
Copy link

ref #568

A design proposal for structurally expressing errors. This PR makes it possible to support custom error messages and i18n. This library will be available for displaying errors to users.

For example, size(string(), 1, 100) outputs the error message ${expected} with a length ${of} but received one with a length of ' ${length}'. This change outputs the following error content in addition to the message. It is possible to format the error message according to the context and language.

interface SizeErrorDetail<T extends number | Date> extends ErrorDetail {
  class: 'size'
  actually: T
  min: T | undefined
  max: T | undefined
  minExlusive: boolean
  maxExlusive: boolean
}
  • todos
    • resolve conflicts
    • think about compatibility

@kamijin-fanta kamijin-fanta marked this pull request as draft February 1, 2021 07:13
@ianstormtaylor
Copy link
Owner

@kamijin-fanta this is cool! A few ideas...

  • I think the E generic should maybe represent just a dictionary of values that will be attached to a struct error instead of needing for it to extends Error itself?
  • I think the details should be mixed directly into the error object, instead of living in a details property.
  • We can make the existing Failure.refinement prop part of the error dictionary properties instead, which is nice. And we can do the same for type too.
  • I don't think the SizeErrorDetail should be common across min/max like that, and instead each refinement should be self-contained.
  • Couldn't tell if this already happens, but it would be good to keep the ability to return true/false instead of requiring using a details object, since this makes the library really easy to pick up for people.
  • The InferError utility is a great idea!

Which would make a min(number(), 0) struct look something like:

Struct<number, null, {
  type: 'number'
} | { 
  refinement: 'min'
  min: 0,
  exclusive: false
}>

And Failure might look like:

type Failure<E extends Record<string, any>> = {
  value: any
  key: any
  branch: Array<any>
  path: Array<any>
  message: string
} & E

@kamijin-fanta
Copy link
Author

@ianstormtaylor Thanks for the idea!

The reason I made min / max common is that I feel that I often need it when displaying error messages. For example, "A value of 10 to 20 is allowed. It was actually 25."

I work on a Failure type change.

@kamijin-fanta
Copy link
Author

Do you have any idea for the definition of toFailure, Result and Validator when rewriting to type Failure E extends Record<string, any> ? For example, it is difficult to generate Failure<E> from the following Result type.

export type Result<E extends Record<string, any>> =
  | boolean
  | string
  | Partial<Failure<E>>
  | Iterable<boolean | string | Partial<Failure<E>>>

It may be possible to solve it by redefining the Result type as follows.

export type DescribedResult<E extends Record<string, any>> =
  | boolean
  | string
  | Partial<Failure<E>>
  | Iterable<boolean | string | Partial<Failure<E>>>

export type SimpleResult = boolean | string | Iterable<boolean | string>

export function define<T>(
  name: string,
  validator: SimpleValidator
): Struct<T, null, {}>;

Also, it can be easily implemented by giving up the type definition for detailed error information. Of course I want to avoid this if possible.

@ianstormtaylor
Copy link
Owner

@kamijin-fanta good question! I tried messing with it in the TypeScript Playground and came up with this approach which may help? It keeps a "props" dictionary as the third argument which then determines which "results" are allowed to be returned by a validation function.

I wasn't sure how to limit it more than object, but it might work for now?

@michael-land
Copy link

Hi, what's the status for this PR?

@kamijin-fanta
Copy link
Author

@xiaoyu-tamu sorry. I couldn't get enough time and left it. I would like to work on it when other work is done, but I would like to welcome other people's contributions.

@haf
Copy link

haf commented Jun 13, 2022

Maybe the maintainers would consider taking this code in and continuing on it?

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

Successfully merging this pull request may close these issues.

4 participants