Git Product home page Git Product logo

modern-errors's Introduction

modern-errors logo

Node Browsers TypeScript Codecov Minified size Mastodon Medium

Handle errors in a simple, stable, consistent way.

Hire me

Please reach out if you're looking for a Node.js API or CLI engineer (11 years of experience). Most recently I have been Netlify Build's and Netlify Plugins' technical lead for 2.5 years. I am available for full-time remote positions.

Features

Simple patterns to:

Stability:

Plugins

Example

Create error classes.

import ModernError from 'modern-errors'

export const BaseError = ModernError.subclass('BaseError')

export const UnknownError = BaseError.subclass('UnknownError')
export const InputError = BaseError.subclass('InputError')
export const AuthError = BaseError.subclass('AuthError')
export const DatabaseError = BaseError.subclass('DatabaseError')

Set error properties.

throw new InputError('Invalid file path', { props: { filePath: '/...' } })

Wrap errors.

try {
  // ...
} catch (cause) {
  throw new InputError('Could not read the file.', { cause })
}

Normalize errors.

try {
  throw 'Missing file path.'
} catch (error) {
  // Normalized from a string to a `BaseError` instance
  throw BaseError.normalize(error)
}

Use plugins.

import ModernError from 'modern-errors'
import modernErrorsSerialize from 'modern-errors-serialize'

export const BaseError = ModernError.subclass('BaseError', {
  plugins: [modernErrorsSerialize],
})

// ...

// Serialize error as JSON, then back to identical error instance
const error = new InputError('Missing file path.')
const errorString = JSON.stringify(error)
const identicalError = BaseError.parse(JSON.parse(errorString))

Install

npm install modern-errors

If any plugin is used, it must also be installed.

npm install modern-errors-{pluginName}

This package works in both Node.js >=18.18.0 and browsers.

This is an ES module. It must be loaded using an import or import() statement, not require(). If TypeScript is used, it must be configured to output ES modules, not CommonJS.

Usage

โ›‘๏ธ Error classes

Create error classes

import ModernError from 'modern-errors'

export const BaseError = ModernError.subclass('BaseError')

export const UnknownError = BaseError.subclass('UnknownError')
export const InputError = BaseError.subclass('InputError')
export const AuthError = BaseError.subclass('AuthError')
export const DatabaseError = BaseError.subclass('DatabaseError')

Export error classes

Exporting and documenting all error classes allows consumers to check them. This also enables sharing error classes between modules.

Check error classes

if (error instanceof InputError) {
  // ...
}

Error subclasses

ErrorClass.subclass() returns a subclass. Parent classes' options are merged with their subclasses.

export const BaseError = ModernError.subclass('BaseError', {
  props: { isError: true },
})
export const InputError = BaseError.subclass('InputError', {
  props: { isUserError: true },
})

const error = new InputError('...')
console.log(error.isError) // true
console.log(error.isUserError) // true
console.log(error instanceof BaseError) // true
console.log(error instanceof InputError) // true

๐Ÿท๏ธ Error properties

Error class properties

const InputError = BaseError.subclass('InputError', {
  props: { isUserError: true },
})
const error = new InputError('...')
console.log(error.isUserError) // true

Error instance properties

const error = new InputError('...', { props: { isUserError: true } })
console.log(error.isUserError) // true

Internal error properties

Error properties that are internal or secret can be prefixed with _. This makes them non-enumerable, which prevents iterating or logging them.

const error = new InputError('...', {
  props: { userId: 6, _isUserError: true },
})
console.log(error.userId) // 6
console.log(error._isUserError) // true
console.log(Object.keys(error)) // ['userId']
console.log(error) // `userId` is logged, but not `_isUserError`

๐ŸŽ€ Wrap errors

Throw errors

throw new InputError('Missing file path.')

Wrap inner error

Any error's message, class and options can be wrapped using the standard cause option.

Instead of being set as a cause property, the inner error is directly merged to the outer error, including its message, stack, name, AggregateError.errors and any additional property.

try {
  // ...
} catch (cause) {
  throw new InputError('Could not read the file.', { cause })
}

Wrap error message

The outer error message is appended, unless it is empty. If the outer error message ends with : or :\n, it is prepended instead.

const cause = new InputError('File does not exist.')
// InputError: File does not exist.
throw new InputError('', { cause })
// InputError: File does not exist.
// Could not read the file.
throw new InputError('Could not read the file.', { cause })
// InputError: Could not read the file: File does not exist.
throw new InputError(`Could not read the file:`, { cause })
// InputError: Could not read the file:
// File does not exist.
throw new InputError(`Could not read the file:\n`, { cause })

Wrap error class

The outer error's class replaces the inner one.

try {
  throw new AuthError('...')
} catch (cause) {
  // Now an InputError
  throw new InputError('...', { cause })
}

Except when the outer error's class is a parent class, such as BaseError.

try {
  throw new AuthError('...')
} catch (cause) {
  // Still an AuthError
  throw new BaseError('...', { cause })
}

Wrap error options

The outer error's props and plugin options are merged.

try {
  throw new AuthError('...', innerOptions)
} catch (cause) {
  // `outerOptions` are merged with `innerOptions`
  throw new BaseError('...', { ...outerOptions, cause })
}

Aggregate errors

The errors option aggregates multiple errors into one. This is like new AggregateError(errors) except that it works with any error class.

const databaseError = new DatabaseError('...')
const authError = new AuthError('...')
throw new InputError('...', { errors: [databaseError, authError] })
// InputError: ... {
//   [errors]: [
//     DatabaseError: ...
//     AuthError: ...
//   ]
// }

๐Ÿšจ Normalize errors

Wrapped errors

Any error can be directly passed to the cause or errors option, even if it is invalid, unknown or not normalized.

try {
  // ...
} catch (cause) {
  throw new InputError('...', { cause })
}

Invalid errors

Manipulating errors that are not Error instances or that have invalid properties can lead to unexpected bugs. BaseError.normalize() fixes that.

try {
  throw 'Missing file path.'
} catch (invalidError) {
  // This fails: `invalidError.message` is `undefined`
  console.log(invalidError.message.trim())
}
try {
  throw 'Missing file path.'
} catch (invalidError) {
  const normalizedError = BaseError.normalize(invalidError)
  // This works: 'Missing file path.'
  // `normalizedError` is a `BaseError` instance.
  console.log(normalizedError.message.trim())
}

๐Ÿž Unknown errors

Handling known errors

Known errors should be handled in a try {} catch {} block and wrapped with a specific class. That block should only cover the statement that might throw in order to prevent catching other unrelated errors.

try {
  return regExp.test(value)
} catch (error) {
  // Now an `InputError` instance
  throw new InputError('Invalid regular expression:', { cause: error })
}

Normalizing unknown errors

If an error is not handled as described above, it is considered unknown. This indicates an unexpected exception, usually a bug. BaseError.normalize(error, UnknownError) assigns the UnknownError class to those errors.

export const UnknownError = BaseError.subclass('UnknownError')
try {
  return regExp.test(value)
} catch (error) {
  // Now an `UnknownError` instance
  throw BaseError.normalize(error, UnknownError)
}

Top-level error handler

Wrapping a module's main functions with BaseError.normalize(error, UnknownError) ensures every error being thrown is valid, applies plugins, and has a class that is either known or UnknownError.

export const main = () => {
  try {
    // ...
  } catch (error) {
    throw BaseError.normalize(error, UnknownError)
  }
}

๐Ÿ”Œ Plugins

List of plugins

Plugins extend modern-errors features. All available plugins are listed here.

Adding plugins

To use a plugin, please install it, then pass it to the plugins option.

npm install modern-errors-{pluginName}
import ModernError from 'modern-errors'

import modernErrorsBugs from 'modern-errors-bugs'
import modernErrorsSerialize from 'modern-errors-serialize'

export const BaseError = ModernError.subclass('BaseError', {
  plugins: [modernErrorsBugs, modernErrorsSerialize],
})
// ...

Custom plugins

Please see the following documentation to create your own plugin.

Plugin options

Most plugins can be configured with options. The option's name is the same as the plugin.

const options = {
  // `modern-errors-bugs` options
  bugs: 'https://github.com/my-name/my-project/issues',
  // `props` can be configured and modified like plugin options
  props: { userId: 5 },
}

Plugin options can apply to (in priority order):

export const BaseError = ModernError.subclass('BaseError', options)
export const InputError = BaseError.subclass('InputError', options)
throw new InputError('...', options)
  • A plugin method call: last argument, passing only that plugin's options
ErrorClass[methodName](...args, options[pluginName])
error[methodName](...args, options[pluginName])

๐Ÿ”ง Custom logic

The custom option can be used to provide an error class with additional methods, constructor, properties or options.

export const InputError = BaseError.subclass('InputError', {
  // The `class` must extend from the parent error class
  custom: class extends BaseError {
    // If a `constructor` is defined, its parameters must be (message, options)
    // Additional `options` can be defined.
    constructor(message, options) {
      message += options?.suffix ?? ''
      super(message, options)
    }

    isUserInput() {
      // ...
    }
  },
})

const error = new InputError('Wrong user name', { suffix: ': example' })
console.log(error.message) // 'Wrong user name: example'
console.log(error.isUserInput())

๐Ÿค“ TypeScript

Please see the following documentation for information about TypeScript types.

API

ModernError

Top-level ErrorClass.

ErrorClass.subclass(name, options?)

name: string
options: ClassOptions?

Creates and returns a child ErrorClass.

options

options.props

Type: object

Error class properties.

options.plugins

Type: Plugin[]

options.custom

Type: class extends ErrorClass {}

Custom class to add any methods, constructor or properties.

options.*

Any plugin options can also be specified.

new ErrorClass(message, options?)

message: string
options: InstanceOptions?
Return value: Error

options

options.props

Type: object

Error instance properties.

options.cause

Type: any

Inner error being wrapped.

options.errors

Type: any[]

Array of errors being aggregated.

options.*

Any plugin options can also be specified.

ErrorClass.normalize(error, NewErrorClass?)

error: Error | any
NewErrorClass: subclass of ErrorClass
Return value: Error

Normalizes invalid errors.

If the error's class is a subclass of ErrorClass, it is left as is. Otherwise, it is converted to NewErrorClass, which defaults to ErrorClass itself.

Modules

This framework brings together a collection of modules which can also be used individually:

Support

For any question, don't hesitate to submit an issue on GitHub.

Everyone is welcome regardless of personal background. We enforce a Code of conduct in order to promote a positive and inclusive environment.

Contributing

This project was made with โค๏ธ. The simplest way to give back is by starring and sharing it online.

If the documentation is unclear or has a typo, please click on the page's Edit button (pencil icon) and suggest a correction.

If you would like to help us fix a bug or add a new feature, please check our guidelines. Pull requests are welcome!

ehmicky
ehmicky

๐Ÿ’ป ๐ŸŽจ ๐Ÿค” ๐Ÿ“–
const_var
const_var

๐Ÿค” ๐Ÿ’ฌ
Andy Brenneke
Andy Brenneke

๐Ÿค” ๐Ÿ’ฌ
Graham Fisher
Graham Fisher

๐Ÿ›
renzor
renzor

๐Ÿ’ฌ ๐Ÿค”
Eugene
Eugene

๐Ÿ’ป ๐Ÿ›
Jonathan Chambers
Jonathan Chambers

โš ๏ธ ๐Ÿ›

modern-errors's People

Contributors

allcontributors[bot] avatar dependabot[bot] avatar ehmicky avatar jmchambers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

modern-errors's Issues

TypeScript + CommonJS support

Guidelines

  • Please search other issues to make sure this bug has not already been reported.
  • If this is related to a typo or the documentation being unclear, please click on the relevant page's Edit button (pencil icon) and suggest a correction instead.

Describe the bug

I am unable to import this library into my codebase. I think it is because the published version is not compiled to module system I can use (?).

It's quite possible there is something on my side that is causing the issue, or some configuration I could change to get it to work, but we already have > 80 other dependencies in our API that are not having any issues importing. (It's an express API)

Thanks in advance for any help, I'm quite excited to give this library a try!

Steps to reproduce

  1. Import and use the library
import ModernError from "modern-errors";

const BaseError = ModernError.subclass("BaseError");
throw new BaseError("test");
  1. Start app with ts-node-dev
  2. See following stack trace:
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/jack/workspace/my-project/api/node_modules/modern-errors/build/src/main.js from /Users/jack/workspace/my-project/api/src/index.ts not supported.
Instead change the require of main.js in /Users/jack/workspace/my-project/api/src/index.ts to a dynamic import() which is available in all CommonJS modules.
    at require.extensions..jsx.require.extensions..js (/private/var/folders/8n/dqgv9b4j797cqd34zb62ythw0000gn/T/ts-node-dev-hook-0371657800851346.js:114:20)
    at Object.nodeDevHook [as .js] (/Users/jack/workspace/my-project/api/node_modules/ts-node-dev/lib/hook.js:63:13)
    at Object.<anonymous> (/Users/jack/workspace/my-project/api/src/index.ts:68:41)
    at Module._compile (/Users/jack/workspace/my-project/api/node_modules/source-map-support/source-map-support.js:547:25)
    at Module.m._compile (/private/var/folders/8n/dqgv9b4j797cqd34zb62ythw0000gn/T/ts-node-dev-hook-0371657800851346.js:69:33)
    at require.extensions..jsx.require.extensions..js (/private/var/folders/8n/dqgv9b4j797cqd34zb62ythw0000gn/T/ts-node-dev-hook-0371657800851346.js:114:20)
    at require.extensions.<computed> (/private/var/folders/8n/dqgv9b4j797cqd34zb62ythw0000gn/T/ts-node-dev-hook-0371657800851346.js:71:20)
    at Object.nodeDevHook [as .ts] (/Users/jack/workspace/my-project/api/node_modules/ts-node-dev/lib/hook.js:63:13)
    at Object.<anonymous> (/Users/jack/workspace/my-project/api/node_modules/ts-node-dev/lib/wrap.js:104:1)
    at Module._compile (/Users/jack/workspace/my-project/api/node_modules/source-map-support/source-map-support.js:547:25)
    at Object.require.extensions..jsx.require.extensions..js (/private/var/folders/8n/dqgv9b4j797cqd34zb62ythw0000gn/T/ts-node-dev-hook-0371657800851346.js:95:24)

Configuration

tsconfig.json

{
  "compilerOptions": {
    "lib": ["es2021"],
    "target": "es2019",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "rootDir": "./",
    "outDir": ".build",
    "allowJs": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "typeRoots": ["node_modules/@types", "generated"],
  },
  "exclude": ["node_modules"]
}

Environment

 System:
   OS: macOS 13.0.1
   CPU: (10) arm64 Apple M1 Pro
   Memory: 158.23 MB / 16.00 GB
   Shell: 5.8.1 - /bin/zsh
 Binaries:
   Node: 16.14.0 - ~/.nvm/versions/node/v16.14.0/bin/node
   Yarn: 1.22.17 - /opt/homebrew/bin/yarn
   npm: 8.18.0 - ~/.nvm/versions/node/v16.14.0/bin/npm
 Browsers:
   Brave Browser: 100.1.37.113
   Chrome: 108.0.5359.124
   Firefox: 107.0.1
   Safari: 16.1

Pull request (optional)

  • I can submit a pull request.

TypeScript issues with `moduleResolution: "nodenext"` and `declaration: true`

Guidelines

  • Please search other issues to make sure this bug has not already been reported.

Describe the bug

When using TypeScript with "moduleResolution: "nodenext" and "declaration": true", it fails to compile the example from README

Steps to reproduce

main.ts

import ModernError from 'modern-errors'
export const BaseError = ModernError.subclass('BaseError')

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "nodenext",
    "declaration": true
  }
}

error:

main.ts:3:14 - error TS2742: The inferred type of 'BaseError' cannot be named without a reference to './node_modules/modern-errors/build/src/subclass/create.js'. This is likely not portable. A type annotation is necessary.

3 export const BaseError = ModernError.subclass('BaseError')
               ~~~~~~~~~

main.ts:3:14 - error TS2742: The inferred type of 'BaseError' cannot be named without a reference to './node_modules/modern-errors/build/src/subclass/custom.js'. This is likely not portable. A type annotation is necessary.

3 export const BaseError = ModernError.subclass('BaseError')
               ~~~~~~~~~


Found 2 errors in the same file, starting at: main.ts:3

I can make it work in two ways -

  1. Disable declaration. However, this means my library cannot publish types and that's not great.
  2. Change to "moduleResolution": "node". However, this means I cannot use the exports settings in my dependencies.

With "moduleResolution":"node" it generates these types for main.d.ts:

export declare const BaseError: import("modern-errors/build/src/subclass/create").ErrorSubclassCore<[], {}, import("modern-errors/build/src/subclass/custom").CustomClass>;

Which hints at the reason for failure: TypeScript has to tap into internal files to reference un-exported types to get ErrorSubclassCore (and, in my real project, CustomClass). With "moduleResolution":"node", this deep linking is not possible, so the TS compiler gives up.

Environment

  System:
    OS: macOS 13.1
    CPU: (8) arm64 Apple M1
    Memory: 64.61 MB / 8.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.14.0 - ~/.asdf/installs/nodejs/18.14.0/bin/node
    Yarn: 1.22.19 - ~/.asdf/shims/yarn
    npm: 9.3.1 - ~/.asdf/plugins/nodejs/shims/npm

Pull request (optional)

  • I can submit a pull request.

How can we differentiate error classes types?

Guidelines

  • Please search other issues to make sure this bug has not already been reported.

Describe the bug

Hello and thanks for this very cool lib!!

Following the README example:

import ModernError from 'modern-errors'

export const BaseError = ModernError.subclass('BaseError')

export const UnknownError = BaseError.subclass('UnknownError')
export const InputError = BaseError.subclass('InputError')
export const AuthError = BaseError.subclass('AuthError')
export const DatabaseError = BaseError.subclass('DatabaseError')

All error classes have the same (TS) type: ErrorSubclassCore<[], {}, CustomClass>, which means that it is impossible to differentiate different errors based on types. For example, the following example compiles:

declare const unknownError: typeof UnknownError
const inputError: typeof InputError = unknownError // no TS error!!

(Also the fact that I have to use typeof is a bit annoying, maybe you have a better solution?)

The reason I am asking this is because I am using fp-ts Either in my app and would like to use modern-errors for the E param, like so:

type MyType = Either<NotFoundError | UnknownError, number>

and be sure that only NotFoundError or UnknownError are tolerated by the compiler, but it is not the case at the moment..

Steps to reproduce

playground here

Environment

  System:
    OS: macOS 11.3.1
    CPU: (8) arm64 Apple M1
    Memory: 277.31 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.15.1 - ~/.nvm/versions/node/v16.15.1/bin/node
    Yarn: 1.22.5 - ~/.yarn/bin/yarn
    npm: 8.11.0 - ~/.nvm/versions/node/v16.15.1/bin/npm
  Browsers:
    Chrome: 109.0.5414.119
    Safari: 14.1
  npmPackages:
    modern-errors: 5.5.1 => 5.5.1 

Pull request (optional)

  • I can submit a pull request.

[Question] ES6 class extensions

Hey this library looks really interesting! We kind of thought it was funny for a package called modern-errors to not use class SomeError extends BaseError, what's the rationale for the .subclass method instead? Less boilerplate to override the constructor?

`errors` property is missing in instance type of custom error

Guidelines

  • Please search other issues to make sure this bug has not already been reported.
  • If this is related to a typo or the documentation being unclear, please click on the relevant page's Edit button (pencil icon) and suggest a correction instead.

Describe the bug

I am exporting type declaration of my custom error with InstanceType<typeof CustomError>. Is this the right way to declare type for CustomErrors?

While declaring using this method I have noticed that the errors property to be missing on the exported type.

This can be reproduce with following code

export const AppError = BaseError.subclass("AppError", {props: {prop1: undefined as string|undefined}})
export type AppErrorType = InstanceType<typeof AppError>
const err: AppErrorType = new AppError("custom error");
err.errors

I get following error when I do type checking.

 error TS2339: Property 'errors' does not exist on type 'SpecificErrorInstance<({ name: "serialize"; getOptions: (options: Options) => Options; isOptions: (options: unknown) => boolean; staticMethods: { serialize: (info: Omit<CommonInfo<never>, "error">, error: unknown) => ErrorObject; parse: (info: Omit<...>, errorObject: unknown) => ErrorInstance; }; instanceMethods: { ...'.

Steps to reproduce

image

Configuration

I am using webstorm as editor. I am using typescript 5.0.0-beta

Environment

System:
OS: macOS 13.1
CPU: (10) arm64 Apple M1 Pro
Memory: 68.75 MB / 32.00 GB
Shell: 3.6.0 - /opt/homebrew/bin/fish
Binaries:
Node: 18.14.0 - ~/Library/pnpm/node
npm: 9.3.1 - ~/Library/pnpm/npm
Browsers:
Chrome: 109.0.5414.119
Chrome Canary: 112.0.5594.3
Firefox: 99.0
Firefox Developer Edition: 107.0
Safari: 16.2
npmPackages:
modern-errors: ^5.5.0 => 5.5.0

Pull request (optional)

  • I can submit a pull request.

support for mandatory props along with type-check support

Guidelines

  • Please search other issues to make sure this feature has not already been requested.

Which problem is this feature request solving?

Thanks for this wonderful library.

Is it possible to define mandatory props. I have a situation where I would like consumer of my error class to pass certain required props.

Describe the solution you'd like

For example,

const BaseError = ModernError.subclass('BaseError', {
	props: {userId: 1}  as {userId: number}
})

const error = new BaseError('Wrong user name', {
	props: {} //would be great if there is type-checking of props here
})

It will be great if when I am creating BaseError, there is a way to prompt/type-check for mandatory props.

Pull request (optional)

  • I can submit a pull request.

SimpleSetProps does not emulate SetProps

Guidelines

  • Please search other issues to make sure this bug has not already been reported.

Describe the bug

SetProps is described here as:

Like LowObject & HighObject except that if both keys are defined,
HighObject overrides LowObject instead of intersecting to it

SimpleSetProps is described here as:

Like SetProps<LowObject, HighObject> except it reduces empty {} for
simpler debugging.

I interpret this to mean that SimpleSetProps and SetProps should have the same behavior for all practical purposes, but that the types emitted by SimpleSetProps might be simpler than SetProps.

I observe that SimpleSetProps and SetProps sometimes produce materially different types. This is because SimpleSetProps does not always give precedence to HighObject like SetProps does. In the case that keyof HighObject extends keyof LowObject, SimpleSetProps<LowObject, HighObject> = LowObject. This means that when the keys of HighObject are a nonempty subset of the keys of LowObject, LowObject overrides HighObject for the keys they share, contradicting the behavior of SetProps.

I believe this can be fixed by simply removing the first conditional type from the definition of SimpleSetProps, as shown in the TS bug workbench below.

Steps to reproduce

https://www.typescriptlang.org/dev/bug-workbench/?#code/PTAEG0HsFsEsBcB0ATR8DOBdAFAC3vAA7oBcIA5grgK4BGiAxjMAKa5wMDWAnsNJMhYAnAHYBaYUMhD0wWgBtItYAEYADINosGtABwrdATi0AmAMwqAbCsMM16gCwqArGssAzN+9oPDKsw7IwOhCDMDU8LDysjAIKGjoAMQAMioqYqkmAJQAUMAAVPk5oPmgybCcLKAABgDKLPAAClLEADzJkADuAPK0AFba8AA0oAASsOS4vQMM8AB81aAsAB4MLITwoAigQizI1GvoS9Ab3DUA3gC+i+7SxaXosCfywqCa1OSUIuSI98A5K0I0k28G4hCqtSehBe9SaLXQrWKZS600GS2W8BYImQRyUM2GSPGk1Rs3RmOxuP6gyGOTmoAAvKBKtxIO4xhMplTSStyTimSwWWyOj0ufAkQB+ZEi-FIkj8wVSkmbHlYvnM1ns4miiWazky0CgOXqoUo0WgABk8o1RL1aJVFNAIhYADdhDrhUqLbqlbLQLDmpA2h7RSMbUq5jk8oV7mUKlVqsH8V6w6LFis1htQPBcABDTawNm0SDZ+VHHO7N4sdywJ3IGklGop-GLSCuoRCWCCI4J03NrYidCYnPIUAamuYmSDGvkLOQLZikr-QHArNgiENANtJGJu0Y1WU-H171m+18vHU2kM0DdODwdq96lWtlNwZ0y0v2aRvJgGuCZbxDAcnHYR3BzNYpVec4kQNaBuAAaQFOVBw7b4AG4ckuSNgKEUDwJtSDoNAWCEO4OURGoaAtCEdDMJyUFwVAAA1WAc39eErzYwMEWFYRQw5YQ5nQwQGHkcsqiYAdNmdFjOOIOVmNYjd4XQ6TFLhLjEGIgV0JAA09P00AAD1xUjeiqgUyFnhYWSjkZSzoWspSuPvTpeN1AShO0USKwkwdQFU+yYScuSmJkqEgvU4gVLCqybM0+DtO-AzkoM4yv109BIHkCJYEgEQAPQKMigbcpKhqGyXKVPitXxBZ0QzfNNl2fZDmOU4LmuUBbiEGNHisoRK1oD4vh+P4AWWIEhBBNdQAAQXkCcRDzWBXUCxzIoRbcH25PcHXPWYjw-ZVdrPENL0ZApjWPJNTyOK6d0-A1JQehdDUXJ9FRPE67oFa0OR9J7rsGX17u2zZLSuo6yX3R0XTdQGXuTf7tQNOUKpe6rbVmCM6JmhT5sW5bVvC9bN1suaFuEJbImJ2Lgu4ro3PwoRBJyYTvPEvK-NUgmqaJ6ySZsuVedEfm1vRxmhExjych5ynRZpgW6Y2+KSJ0sAUs1rWDTSpKReplalYcmzQEHKJ5FN8KC1gFgjmzKozKOdwpGgP16f7UBsDzUAXhzQcsizXBbfEv3bdxhiABFYHQPpIHHE27Pp1ormllmkp1kzw6qKOY7jkR4H1sXBfdxlC8V8Wk5T9y090jPTJmgBRABHagc3kBO3Y21pmdTiNa6MzOzNAZvW-kMvDYrjar3H2njaTnvq77jWB6AA

Environment

  System:
    OS: macOS 13.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 64.67 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.12.1 - ~/.nvm/versions/node/v18.12.1/bin/node
    Yarn: 3.2.1 - /Users/Shared/ironclad/git/ironclad_org/ironclad/harbor/node_modules/.bin/yarn
    npm: 8.19.2 - ~/.nvm/versions/node/v18.12.1/bin/npm
  Browsers:
    Chrome: 109.0.5414.119
    Safari: 16.2

Pull request (optional)

  • I can submit a pull request.

Typescript constructor example?

Hi there, love the library so far but am struggling with a basic use case in Typescript and am hoping you could provide guidance to help beef up the typescript example section.

I have a HashMismatchError that receives two props.

throw new HashMismatchError(
  `Hash mismatch: expected ${stored.hashValue} but got ${foundHashValue}`,
  {
    props: {
      foundHash: foundHashValue,
      storedHash: stored.hashValue,
    },
  },
)

Its defined like this:

export const HashMismatchError = ModernError.subclass("HashMismatchError", {
  custom: class extends ModernError {
    foundHash: string
    storedHash: string
    constructor(
      message: string,
      options: InstanceOptions<Plugins> | undefined,
    ) {
      super(message, options)
      // @ts-expect-error can't figure out how to type this
      this.foundHash = options?.props?.foundHash
      // @ts-expect-error can't figure out how to type this
      this.storedHash = options?.props?.storedHash
    }
  },
})

Could you provide any guidance on how to clean up the constructor function signature and hash variable assignments? It would help me and others understand how to use constructor functions with the library. Thanks for your awesome lib!

Why not to support both ESM and CommonJS?

Hi! Thanks for your awesome work regarding modern-errors, but I have a one problem with this library. It just doesn't work without ESM completely. I've seen this issue #3 and I get your points, but I wonder why it's not possible for a library to support temporarily both CommonJS and ESM. I would love to use this library in my project, but due to it's dependencies it's impossible to migrate towards pure ESM setup. I tried it, but I encounter like infinite flow of bugs in deps.
image
Here is a screenshot from another library that just handles it well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.