Skip to content

Conversation

@justjake
Copy link
Contributor

@justjake justjake commented Jan 8, 2019

This PR builds on the changes in #6, so it'd be best to merge that before reviewing, or start reviewing after the duplicated commits.

Major changes:

  • Add .toString() method to all Types which returns a typescript-like representation of the type instance. This allows us to print types in error messages.
  • A much richer Err type that tracks path, error causes, and error types.
    • Err messages can be lazy () => string instead of string, avoiding expensive string building unless an exception is being raised, which makes Type#sliceResult even expensive.
  • A custom Error class thrown for assertions, StructuralError, which collects the root causes of a type error, enumerating the keys that did not match an expected type.

Example of exception output:

StructuralError: given value
  { owner: { username: 'the duke', age: 42, email: 'duke.nuke@example.com' },
    contents: 
     [ { text: 'Those who do not study history are doomed to repeat it',
         author: 'Albert Einstien',
         date: 1970-01-01T00:00:02.001Z },
       { uri: 'example.com',
         alt: 'Mr. Doctor Albert Einstien wearing a tweed jacket' } ] }
did not match expected type
  { owner: { username: string,
      age?: number,
      email: string & validate(has @ symbol, (val) => !!val.match(/@/)) },
    contents: Array<{ text: string, author: string, date?: Date } |
    { uri: string & validate(starts with http, (val) => !!val.match(/^http/)),
      alt: string }> }
because: at .contents[1]: given value
    { uri: 'example.com',
      alt: 'Mr. Doctor Albert Einstien wearing a tweed jacket' }
  did not match expected type
    { text: string, author: string, date?: Date } |
    { uri: string & validate(starts with http, (val) => !!val.match(/^http/)),
      alt: string }
  because: matched none of 2 types:
    | { text: string, author: string, date?: Date }
      failed multiple checks:
      - at .text: given value `undefined` did not match expected type `string`:
        key missing
      - at .author: given value `undefined` did not match expected type `string`:
        key missing
    | { uri: string & validate(starts with http, (val) => !!val.match(/^http/)),
        alt: string }
      at .uri: given value `'example.com'` did not match expected type
        validate(starts with http, (val) => !!val.match(/^http/))
      because: validation returned false

That exception has these root causes:

se.causes.forEach(c => { console.log(c.toString()); })
  console.log test/errors.ts:141
    at .contents[1].text: given value `undefined` did not match expected type `string`:
      key missing

  console.log test/errors.ts:141
    at .contents[1].author: given value `undefined` did not match expected type `string`:
      key missing

  console.log test/errors.ts:141
    at .contents[1].uri: given value `'example.com'` did not match expected type
      validate(starts with http, (val) => !!val.match(/^http/))
    because: validation returned false

justjake added 10 commits June 10, 2019 09:21
- errors now track significantly more information, such as the path
  where they occurred, the bad value, the expected type, and
  any underlying causes of the error.
- standardized formatting of error messages, including when errors are
  embedded in other errors
- use NodeJS util.inspect for printing values instead of toString()
  because the average JS object is just represented as `[object Object]`
- Errors from Either types pretty-print each type case and why it failed
- revised .toString() for Either and Intersect types

TODO: some tests for this
@justjake
Copy link
Contributor Author

@reissbaker bump

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.

1 participant