Comparing version 2.0.0-12 to 2.0.0
@@ -7,2 +7,3 @@ declare const INTERNAL: unique symbol; | ||
declare type ObjTypesBase = Record<string, any>; | ||
declare type GetMessage<Data> = (data: Data, declaration: ErreurDeclaration<Data>) => string; | ||
/** | ||
@@ -16,2 +17,3 @@ * This is like a key to instantiate an Erreur and extract its data | ||
readonly withTransform: <Params extends readonly any[]>(transform: (...params: Params) => Data) => ErreurDeclaration<Data, Params>; | ||
readonly withMessage: (message: string | GetMessage<Data>) => ErreurDeclaration<Data, Params>; | ||
readonly create: (...params: Params) => Erreur; | ||
@@ -25,2 +27,3 @@ readonly createWithCause: (cause: Erreur, ...params: Params) => Erreur; | ||
private [INTERNAL]; | ||
static readonly DEFAULT_MESSAGE: GetMessage<any>; | ||
/** | ||
@@ -72,3 +75,3 @@ * Make sure the function either returns a value or throws an Erreur instance | ||
cause?: Error | undefined; | ||
static declare<Data>(name: string): ErreurDeclaration<Data>; | ||
static declare<Data>(name: string, message?: string | GetMessage<Data>): ErreurDeclaration<Data>; | ||
private constructor(); | ||
@@ -96,3 +99,3 @@ is(type: ErreurDeclarationAny): boolean; | ||
}> | undefined; | ||
declare function declareWithTransform<Data, Params extends readonly any[]>(name: string, transform: (...params: Params) => Data): ErreurDeclaration<Data, Params>; | ||
declare function declareWithTransform<Data, Params extends readonly any[]>(name: string, transform: (...params: Params) => Data, message?: string | GetMessage<Data>): ErreurDeclaration<Data, Params>; | ||
declare type CreatorsBase = Record<string, (...args: any[]) => any>; | ||
@@ -105,2 +108,2 @@ declare type ErreursFromCreators<Creators extends CreatorsBase> = { | ||
export { CreatorsBase, DataFromTypes, Erreur, ErreurDeclaration, ErreurDeclarationAny, ErreursFromCreators, ObjDeclarationsBase, ObjTypesBase, OnError, resolve, resolveAsync, wrap, wrapAsync }; | ||
export { CreatorsBase, DataFromTypes, Erreur, ErreurDeclaration, ErreurDeclarationAny, ErreursFromCreators, GetMessage, ObjDeclarationsBase, ObjTypesBase, OnError, resolve, resolveAsync, wrap, wrapAsync }; |
@@ -33,3 +33,3 @@ var __defProp = Object.defineProperty; | ||
constructor(internal) { | ||
super(`[Erreur]: ${internal.declaration.name} ${JSON.stringify(internal.data)}`); | ||
super(`[Erreur]: ${internal.message}`); | ||
this[INTERNAL] = internal; | ||
@@ -40,6 +40,7 @@ this.erreurCause = internal.erreurCause; | ||
} | ||
static declare(name) { | ||
static declare(name, message = _Erreur.DEFAULT_MESSAGE) { | ||
const symbol = Symbol(`[Erreur]: ${name}`); | ||
return declareWithTransform2((data) => data); | ||
function declareWithTransform2(transform) { | ||
return declareInternal((data) => data, message); | ||
function declareInternal(transform, getMessage) { | ||
const getMessageResolved = typeof getMessage === "string" ? () => getMessage : getMessage; | ||
const type = { | ||
@@ -49,8 +50,15 @@ [INTERNAL]: symbol, | ||
name, | ||
create: (...params) => new _Erreur({ declaration: type, data: transform(...params) }), | ||
createWithCause: (cause, ...params) => new _Erreur({ declaration: type, data: transform(...params), erreurCause: cause }), | ||
create: (...params) => { | ||
const data = transform(...params); | ||
return new _Erreur({ declaration: type, data, message: getMessageResolved(data, type) }); | ||
}, | ||
createWithCause: (cause, ...params) => { | ||
const data = transform(...params); | ||
return new _Erreur({ declaration: type, data, erreurCause: cause, message: getMessageResolved(data, type) }); | ||
}, | ||
is: (error) => is(error, type), | ||
match: (error) => match(error, type), | ||
matchExec: (error, fn) => matchExec(error, type, fn), | ||
withTransform: (subTransform) => declareWithTransform2(subTransform) | ||
withTransform: (subTransform) => declareInternal(subTransform, getMessage), | ||
withMessage: (subMessage) => declareInternal(transform, subMessage) | ||
}; | ||
@@ -69,2 +77,3 @@ return type; | ||
INTERNAL; | ||
Erreur.DEFAULT_MESSAGE = (data, declaration) => `${declaration.name} ${JSON.stringify(data)}`; | ||
Erreur.wrap = wrap; | ||
@@ -163,4 +172,4 @@ Erreur.wrapAsync = wrapAsync; | ||
} | ||
function declareWithTransform(name, transform) { | ||
return Erreur.declare(name).withTransform(transform); | ||
function declareWithTransform(name, transform, message) { | ||
return Erreur.declare(name, message).withTransform(transform); | ||
} | ||
@@ -167,0 +176,0 @@ function declareMany(creators) { |
{ | ||
"name": "erreur", | ||
"version": "2.0.0-12", | ||
"version": "2.0.0", | ||
"description": "Type safe custom errors", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
109
README.md
@@ -64,2 +64,19 @@ # 🛑 Erreur | ||
#### Custom message | ||
By default the `Erreur` instance will have a message that is the name of the error followed by the data stringified as JSON. | ||
You can override this behavior by passing a custom message as the second parameter of the `Erreur.declare` method. | ||
```ts | ||
const MyError = Erreur.declare<{ count: number }>('MyError', (data) => `Count is ${data.count}`); | ||
``` | ||
You can also use the `withMessage` method of an `ErreurDeclaration` to create a clone of the declaration with a custom message. | ||
```ts | ||
const MyError = Erreur.declare<{ count: number }>('MyError'); | ||
const MyErrorWithMessage = MyError.withMessage((data) => `Count is ${data.count}`); | ||
``` | ||
#### Decalaring multiple errors | ||
@@ -139,10 +156,96 @@ | ||
#### Error `cause` and `erreurCause` | ||
#### Erreur `cause` and `erreurCause` | ||
Erreur supports the cause property of the native `Error` class. This property can be used to store the original error that caused the current error. | ||
With Erreur this `cause` must be an `Erreur` instance, you can access the `erreurCause` property to get the correct typing. | ||
To set the cause of an Erreur, use the `createWithCause` method of the declaration. | ||
```ts | ||
const SubErreur = Erreur.declare<{ message: string }>('SubErreur'); | ||
const MyErreur = Erreur.declare<{ message: string }>('MyErreur'); | ||
const subError = SubErreur.create({ message: 'Hello world' }); | ||
const error = MyErreur.createWithCause({ message: 'Hello world' }, subError); | ||
// error.cause === subError | ||
// error.erreurCause === subError | ||
``` | ||
#### `warp` and `wrapAsync` | ||
Wrap a function to make sure it either returns a value or throws an `Erreur` instance. | ||
Wrap a function to make sure it either returns a value or throws an `Erreur` instance. Not that this function does not care about what is inside the `Erreur` instance, it only checks that it is an instance of `Erreur`. | ||
#### `resolve` and `resolveAsync` | ||
Smae as `wrap` and `wrapAsync` but returns the `Erreur` instance instead of throwing it. | ||
Same as `wrap` and `wrapAsync` but returns the `Erreur` instance instead of throwing it. | ||
## Exposing Erreurs | ||
One of the main goal of Erreur is to allow you to expose your errors to the outside world without creating one `Error` class for each error. | ||
Say you want to build a wrapper around [`fetch`](https://developer.mozilla.org/fr/docs/Web/API/Fetch_API). You want to do some custom validation on the response and throw an error if the response is not valid. Rather than throwing random `Errors` or creating a new `Error` class for each error, you can use Erreur to create collections of Erreurs your wrapper can throw. | ||
```ts | ||
export const BetterFetchErreurs = Erreur.declareMany({ | ||
ResponseNotOK: (response: Response) => ({ response }), | ||
InvalidBody: () => null, | ||
}); | ||
export async function betterFetch() { | ||
// ... | ||
if (!response.ok) { | ||
throw BetterFetchErreurs.ResponseNotOK.create(response); | ||
} | ||
} | ||
``` | ||
Now when someone uses your wrapper, they can catch the error and extract the data from it. | ||
```ts | ||
import { betterFetch, BetterFetchErreurs } from './better-fetch'; | ||
try { | ||
await betterFetch(); | ||
} catch (err) { | ||
if (Erreur.is(err, BetterFetchErreurs.ResponseNotOK)) { | ||
// response is not ok | ||
} | ||
} | ||
``` | ||
In fact we probably want to hanlde all the possible errors our wrapper can throw, so we can use `Erreur.matchObj` to check if the error is one of the errors in our collection. | ||
```ts | ||
import { betterFetch, BetterFetchErreurs } from './better-fetch'; | ||
try { | ||
await betterFetch(); | ||
} catch (err) { | ||
const matched = Erreur.matchObj(err, BetterFetchErreurs); | ||
if (matched) { | ||
// { kind: 'ResponseNotOK', data: { response: Response } } | { kind: 'InvalidBody', data: null } | ||
} | ||
} | ||
``` | ||
You can also "combine" multiple collections of errors into a single one, for example you might have a `validator` function that expose its own errors: | ||
```ts | ||
try { | ||
const data = await betterFetch(); | ||
return validator(data); | ||
} catch (err) { | ||
const matched = Erreur.matchObj(err, { | ||
...BetterFetchErreurs, | ||
...ValidatorErreurs, | ||
}); | ||
if (matched) { | ||
// Here we can hendle the error depending on the kind | ||
// { kind: 'ResponseNotOK', data: { response: Response } } | { kind: 'InvalidBody', data: null } | { kind: 'InvalidEmail', data: string } | ||
} | ||
// Error not handled | ||
throw err; | ||
} | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
26490
453
0
250