neverthrow
Advanced tools
Comparing version 2.7.1 to 2.8.0-beta.0
@@ -371,2 +371,35 @@ 'use strict'; | ||
/** | ||
* Short circuits on the FIRST Err value that we find | ||
*/ | ||
var combineResultList = function (resultList) { | ||
return resultList.reduce(function (acc, result) { | ||
return acc.isOk() | ||
? result.isErr() | ||
? err(result.error) | ||
: acc.map(function (values) { return values.concat(result.value); }) | ||
: acc; | ||
}, ok([])); | ||
}; | ||
/* This is the typesafe version of Promise.all | ||
* | ||
* Takes a list of ResultAsync<T, E> and success if all inner results are Ok values | ||
* or fails if one (or more) of the inner results are Err values | ||
*/ | ||
var combineResultAsyncList = function (asyncResultList) { | ||
return ResultAsync.fromPromise(Promise.all( | ||
// need to cast each ResultAsync into a Promise by calling .then | ||
// in order to avoid compilation errors / type mismatches | ||
asyncResultList.map(function (resultAsync) { return resultAsync.then(function (a) { return a; }); }))).andThen(combineResultList); | ||
}; | ||
// eslint-disable-next-line | ||
function combine(list) { | ||
if (list[0] instanceof ResultAsync) { | ||
return combineResultAsyncList(list); | ||
} | ||
else { | ||
return combineResultList(list); | ||
} | ||
} | ||
exports.Err = Err; | ||
@@ -382,2 +415,3 @@ exports.Ok = Ok; | ||
exports.chain8 = chain8; | ||
exports.combine = combine; | ||
exports.err = err; | ||
@@ -384,0 +418,0 @@ exports.errAsync = errAsync; |
@@ -57,2 +57,5 @@ declare type Result<T, E> = Ok<T, E> | Err<T, E>; | ||
export { Err, Ok, Result, ResultAsync, chain, chain3, chain4, chain5, chain6, chain7, chain8, err, errAsync, ok, okAsync }; | ||
declare function combine<T, E>(resultList: Result<T, E>[]): Result<T[], E>; | ||
declare function combine<T, E>(asyncResultList: ResultAsync<T, E>[]): ResultAsync<T[], E>; | ||
export { Err, Ok, Result, ResultAsync, chain, chain3, chain4, chain5, chain6, chain7, chain8, combine, err, errAsync, ok, okAsync }; |
@@ -367,2 +367,35 @@ // eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
export { Err, Ok, ResultAsync, chain, chain3, chain4, chain5, chain6, chain7, chain8, err, errAsync, ok, okAsync }; | ||
/** | ||
* Short circuits on the FIRST Err value that we find | ||
*/ | ||
var combineResultList = function (resultList) { | ||
return resultList.reduce(function (acc, result) { | ||
return acc.isOk() | ||
? result.isErr() | ||
? err(result.error) | ||
: acc.map(function (values) { return values.concat(result.value); }) | ||
: acc; | ||
}, ok([])); | ||
}; | ||
/* This is the typesafe version of Promise.all | ||
* | ||
* Takes a list of ResultAsync<T, E> and success if all inner results are Ok values | ||
* or fails if one (or more) of the inner results are Err values | ||
*/ | ||
var combineResultAsyncList = function (asyncResultList) { | ||
return ResultAsync.fromPromise(Promise.all( | ||
// need to cast each ResultAsync into a Promise by calling .then | ||
// in order to avoid compilation errors / type mismatches | ||
asyncResultList.map(function (resultAsync) { return resultAsync.then(function (a) { return a; }); }))).andThen(combineResultList); | ||
}; | ||
// eslint-disable-next-line | ||
function combine(list) { | ||
if (list[0] instanceof ResultAsync) { | ||
return combineResultAsyncList(list); | ||
} | ||
else { | ||
return combineResultList(list); | ||
} | ||
} | ||
export { Err, Ok, ResultAsync, chain, chain3, chain4, chain5, chain6, chain7, chain8, combine, err, errAsync, ok, okAsync }; |
{ | ||
"name": "neverthrow", | ||
"version": "2.7.1", | ||
"version": "2.8.0-beta.0", | ||
"description": "Stop throwing errors, and instead return Results!", | ||
@@ -27,20 +27,20 @@ "main": "dist/index.cjs.js", | ||
"devDependencies": { | ||
"@babel/core": "7.10.5", | ||
"@babel/preset-env": "7.10.4", | ||
"@babel/core": "7.11.6", | ||
"@babel/preset-env": "7.11.5", | ||
"@babel/preset-typescript": "7.10.4", | ||
"@types/jest": "26.0.7", | ||
"@types/node": "14.0.23", | ||
"@typescript-eslint/eslint-plugin": "3.6.1", | ||
"@typescript-eslint/parser": "3.6.1", | ||
"babel-jest": "26.1.0", | ||
"eslint": "7.4.0", | ||
"eslint-config-prettier": "6.11.0", | ||
"@types/jest": "26.0.14", | ||
"@types/node": "14.11.2", | ||
"@typescript-eslint/eslint-plugin": "4.2.0", | ||
"@typescript-eslint/parser": "4.2.0", | ||
"babel-jest": "26.3.0", | ||
"eslint": "7.9.0", | ||
"eslint-config-prettier": "6.12.0", | ||
"eslint-plugin-prettier": "3.1.4", | ||
"jest": "26.1.0", | ||
"prettier": "2.0.5", | ||
"rollup": "2.22.2", | ||
"rollup-plugin-dts": "1.4.8", | ||
"rollup-plugin-typescript2": "0.27.1", | ||
"ts-jest": "26.1.3", | ||
"typescript": "3.9.7" | ||
"jest": "26.4.2", | ||
"prettier": "2.1.2", | ||
"rollup": "2.28.2", | ||
"rollup-plugin-dts": "1.4.13", | ||
"rollup-plugin-typescript2": "0.27.3", | ||
"ts-jest": "26.4.0", | ||
"typescript": "4.0.3" | ||
}, | ||
@@ -47,0 +47,0 @@ "keywords": [ |
189
README.md
@@ -5,2 +5,4 @@ # NeverThrow 🙅 | ||
If you find this package useful, please consider [sponsoring me](https://github.com/sponsors/supermacro/) or simply [buying me a coffee](https://ko-fi.com/gdelgado)! | ||
## Description | ||
@@ -15,4 +17,2 @@ | ||
`neverthrow` also exposes `chain(...)` methods for chaining asynchronous tasks in a functional style ([docs below](#chaining-api)). However, these methods might be deprecated in the future. It is advised to use the `ResultAsync` instead. | ||
[Read the blog post](https://gdelgado.ca/type-safe-error-handling-in-typescript.html#title) which explains _why you'd want to use this package_. | ||
@@ -142,9 +142,14 @@ | ||
- `errAsync` convenience function to create a `ResultAsync` containing an `Err` type `Result` | ||
- `chain` and all of its variants ([docs below](#chaining-api)) - for chaining sequential asynchronous operations that return `Result`s | ||
```typescript | ||
import { ok, Ok, err, Err, Result } from 'neverthrow' | ||
// chain api available as well | ||
import { chain, chain3, chain4, chain5, chain6, chain7, chain8 } from 'neverthrow' | ||
import { | ||
ok, | ||
Ok, | ||
err, | ||
Err, | ||
Result, | ||
okAsync, | ||
errAsync, | ||
ResultAsync | ||
} from 'neverthrow' | ||
``` | ||
@@ -759,172 +764,2 @@ | ||
--- | ||
# 🔗 | ||
## Chaining API | ||
> Disclaimer: the preferred solution to chaining asynchronous tasks is `ResultAsync`. | ||
> The following method might be deprecated in the future. | ||
tldr: `chain` is the `.andThen` equivalent for `Result`s wrapped inside of a `Promise`. | ||
> Examples can be found in the [tests directory](https://github.com/gDelgado14/neverthrow/blob/master/tests/index.test.ts#L235) | ||
The `chain` functions allow you to create sequential execution flows for asynchronous tasks in a very elegant way. | ||
If you try to create sequential execution flows for, say 3 or more, async tasks using the `asyncMap` method, you will end up with nested code (hello callback hell) and a lot of manually unwrapping promises using `await`. | ||
`chain` takes care of unwrapping `Promise`s for you. | ||
**Chains have short-circuit behaviour**: | ||
One of the properties of the `chain` api (thanks to the way `Result`s work), is that the chain returns early (or short circuits) once any computation returns a `Err` variant. | ||
All `chain` functions require that: | ||
- the **first** argument be a promise with `Result` inside it. | ||
- the **last** argument be a function that returns a promise with `Result` inside it. | ||
All arguments **in between** the first and the last do not need to be async! You'll see this in the function signatures of `chain3`, `chain4`, `chain5`, etc ... | ||
Here's an example using `chain4` ([source](https://github.com/parlez-vous/server/blob/19e34464863b04ae41efccad610be6fa967d5833/src/routes/admins/sites/get-single.ts#L20)): | ||
```typescript | ||
import { ok, chain4 } from 'neverthrow' | ||
// ... | ||
chain4( | ||
sessionManager.getSessionUser(), | ||
({ id }) => getSingleSite(id, siteId), | ||
fetchSiteWithComments, | ||
siteWithComments => Promise.resolve(ok(buildSite(siteWithComments))), | ||
) | ||
``` | ||
### `chain` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>>, | ||
): Promise<Result<T2, E>> => { ... } | ||
``` | ||
The above in plain english: | ||
- given a computation `r1` | ||
- evaluate `r2` with the `Ok` value of `r1` as r2`'s argument. | ||
- If `r1` ends up being an `Err` value, then do not evaluate `r2`, and instead return the `Err` | ||
### `chain3` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>>, | ||
): Promise<Result<T3, E>> => { ... } | ||
``` | ||
Same thing as `chain`, except now you have a middle computation which can be either synchronous or asynchronous. | ||
### `chain4` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, T4, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>> | Result<T3, E>, | ||
r4: (v: T3) => Promise<Result<T4, E>>, | ||
): Promise<Result<T4, E>> => { ... } | ||
``` | ||
Same thing as `chain`, except now you have 2 middle computations; any of which can be either synchronous or asynchronous. | ||
### `chain5` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, T4, T5, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>> | Result<T3, E>, | ||
r4: (v: T3) => Promise<Result<T4, E>> | Result<T4, E>, | ||
r5: (v: T4) => Promise<Result<T5, E>>, | ||
): Promise<Result<T5, E>> => { ... } | ||
``` | ||
Same thing as `chain`, except now you have 3 middle computations; any of which can be either synchronous or asynchronous. | ||
### `chain6` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, T4, T5, T6, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>> | Result<T3, E>, | ||
r4: (v: T3) => Promise<Result<T4, E>> | Result<T4, E>, | ||
r5: (v: T4) => Promise<Result<T5, E>> | Result<T5, E>, | ||
r6: (v: T5) => Promise<Result<T6, E>>, | ||
): Promise<Result<T6, E>> => { | ||
``` | ||
Same thing as `chain`, except now you have 4 middle computations; any of which can be either synchronous or asynchronous. | ||
### `chain7` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, T4, T5, T6, T7, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>> | Result<T3, E>, | ||
r4: (v: T3) => Promise<Result<T4, E>> | Result<T4, E>, | ||
r5: (v: T4) => Promise<Result<T5, E>> | Result<T5, E>, | ||
r6: (v: T5) => Promise<Result<T6, E>> | Result<T6, E>, | ||
r7: (v: T6) => Promise<Result<T7, E>>, | ||
): Promise<Result<T7, E>> => { ... } | ||
``` | ||
Same thing as `chain`, except now you have 5 middle computations; any of which can be either synchronous or asynchronous. | ||
### `chain8` | ||
**Signature:** | ||
```typescript | ||
<T1, T2, T3, T4, T5, T6, T7, T8, E>( | ||
r1: Promise<Result<T1, E>>, | ||
r2: (v: T1) => Promise<Result<T2, E>> | Result<T2, E>, | ||
r3: (v: T2) => Promise<Result<T3, E>> | Result<T3, E>, | ||
r4: (v: T3) => Promise<Result<T4, E>> | Result<T4, E>, | ||
r5: (v: T4) => Promise<Result<T5, E>> | Result<T5, E>, | ||
r6: (v: T5) => Promise<Result<T6, E>> | Result<T6, E>, | ||
r7: (v: T6) => Promise<Result<T7, E>> | Result<T7, E>, | ||
r8: (v: T7) => Promise<Result<T8, E>>, | ||
): Promise<Result<T8, E>> => { ... } | ||
``` | ||
Same thing as `chain`, except now you have 5 middle computations; any of which can be either synchronous or asynchronous. | ||
-- | ||
## Wrapping a Dependency that throws | ||
> incomplete documenation ... | ||
> Examples to come soon | ||
- axios | ||
- knex | ||
## A note on the Package Name | ||
@@ -931,0 +766,0 @@ |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
856
61130
1
768