Useful type to model success and failure
npm install resultageA clear way for handling success and failure in both synchronous and asynchronous operations.
``bash`
npm install resultage
`typescript
import { Result, ok, err } from 'resultage';
type JsonObject = Record
const okIfObject = (value: unknown): Result
typeof value === 'object' && value !== null && !Array.isArray(value)
? ok(value as JsonObject)
: err('ERR_NOT_AN_OBJECT');
const okIfInt = (value: unknown): Result
Number.isInteger(value)
? ok(value as number)
: err('ERR_NOT_AN_INT');
const okIfString = (value: unknown): Result
typeof value === 'string'
? ok(value)
: err('ERR_NOT_A_STRING');
`
`typescript
type Person = {
name: string;
age: number;
}
const okIfPerson = (value: unknown): Result
Do(function*() {
const obj = yield* okIfObject(value);
const name = yield* okIfString(obj.name);
const age = yield* okIfInt(obj.age);
return { name, age };
}).mapErr(() => 'ERR_NOT_A_PERSON');
const person: Person = okIfPerson({ name: 'John', age: 42 }).unwrap();
`
`typescript`
const okIfPerson =
(value: unknown) => okIfObject(value).chain(
(obj) => okIfString(obj.name).chain(
(name) => okIfInt(obj.age).chain(
(age) => ok({ name, age })
)));
or the same with map on the last step:
`typescript`
const okIfPerson =
(value: unknown) => okIfObject(value).chain(
(obj) => okIfString(obj.name).chain(
(name) => okIfInt(obj.age).map(
(age) => ({ name, age })
)));
> Note: from the performance perspective, using chain is preferable to Do-notation,chain
> because doesn't create and run generators.Do
> However, -notation is more readable and easier to use.
> Additionally, the formatting of the code in this section requires specific
> linters and formatters configuration.
`typescript
const lordOfTheRingsAuthors = collect([
ok({ id, name: 'J. R. R. Tolkien' }),
ok({ id, name: 'Christopher Tolkien' }),
]);
const silmarillionAuthors = collect([
ok({ id, name: 'J. R. R. Tolkien' }),
err('ERR_PERSON_NOT_FOUND' as const),
]);
console.log(lordOfTheRingsAuthors.unwrap());
// Prints to console:
// [
// { id, name: 'J. R. R. Tolkien' },
// { id, name: 'Christopher Tolkien' }
// ]
console.log(silmarillionAuthors.unwrapErr());
// Prints to console: ERR_PERSON_NOT_FOUND
`
`typescript
import { Do, collect, err, ok } from 'resultage';
const getBookWithAuthors = (bookId: string) =>
Do(async function* () {
const book = yield* await fetchBook(bookId);
const authors = yield* await fetchPersons(book.authorIds);
return { ...book, authors };
});
const fetchBook = async (id: string) => (
id === '1' ? ok({ id, title: 'The Lord of the Rings', authorIds: ['1', '2'] }) :
id === '2' ? ok({ id, title: 'The Silmarillion', authorIds: ['1', '3'] }) :
err('ERR_BOOK_NOT_FOUND' as const)
);
const fetchPersons = async (ids: string[]) => collect(
ids.map(id => (
id === '1' ? ok({ id, name: 'J. R. R. Tolkien' }) :
id === '2' ? ok({ id, name: 'Christopher Tolkien' }) :
err("ERR_PERSON_NOT_FOUND" as const)
))
);
async function run() {
const LordOfTheRings = await getBookWithAuthors('1');
console.log(LordOfTheRings.unwrap());
// Prints to console book with authors populated
const Silmarillion = await getBookWithAuthors('2');
console.log(Silmarillion.unwrapErr());
// Prints to console: ERR_PERSON_NOT_FOUND
const TheHobbit = await getBookWithAuthors('3');
console.log(TheHobbit.unwrapErr());
// Prints to console: ERR_BOOK_NOT_FOUND
}
run().catch(console.error);
`
[TODO: insert link to documentation]
Result is a generic type that represents either success or failure, andOkResult
is a union of and ErrResult types:`
typescript`
type Result
Where:
- OkResult is a type that represents success and wraps the value of type T.ErrResult
- is a type that represents failure and wraps the error of type E.
OkResult is an interface that maps to the success result with the following structure.
`typescript`
interface OkResult
readonly value: T;
readonly isOk: true;
readonly isErr: false;
readonly isError: false;
/ ... methods ... /
}
The property value is accessible only when the type of the corresponding variableResult
or parameter is narrowed from the to the OkResult.
To narrow the type of the variable or parameter to OkResult, use the isOk methodResult
on the instance.
Note: OkResult is an interface, not a class, so it is not possible to createOkResult
an instance of directly. Use the ok function to create an instance of OkResult.
ErrResult is an interface that maps to the failure result with the following structure.
`typescript`
interface ErrResult
readonly error: E;
readonly isOk: false;
readonly isErr: true;
readonly isError: true;
/ ... methods ... /
}
The property error is accessible only when the type of the corresponding variableResult
or parameter is narrowed from the to the ErrResult.
To narrow the type of the variable or parameter to ErrResult, use either the isErrisError
or the method on the Result instance.
Note: ErrResult is an interface, not a class, so it is not possible to createErrResult
an instance of directly. Use the err function to create an instance of ErrResult.
The following methods are common to both OkResult and ErrResult:
`typescript`
interface Result
map(fn: (data: T) => S): Result;
mapErr
chain(next: (data: T) => Result): Result;
chainErr(next: (error: E) => Result): Result
unwrap(): T;
unwrapOr(fallback: S): T | S;
unwrapOrElse(fallback: (error: E) => S): T | S;
unwrapErr(): E;
unwrapErrOr
unwrapErrOrElse
unwrapOrThrow(): T;
unpack(): T | E;
match
okMatcher: (data: T) => TR,
errMatcher: (error: E) => ER,
): ER | TR;
tap(fn: (data: T) => void): Result
tapErr(fn: (error: E) => void): Result
biMap(okFn: (data: T) => S, errFn: (error: E) => F): Result;
biChain
okFn: (data: T) => Result
errFn: (error: E) => Result
): Result
[Symbol.iterator](): Generator
}
As mentioned above, OkResult and ErrResult are interfaces, not classes, so it is notOkResult
possible to create an instance of or ErrResult directly. Use the followingOkResult
functions to create an instance of or ErrResult.
Creates an instance of OkImpl class (that is not exported from the package).
Function Signature:
`typescript`
const ok:
Example:
`typescript
import { ok } from 'resultage';
const okNumber = ok(42);
`
Creates an instance of ErrImpl class (that is not exported from the package).
Function Signature:
`typescript`
const err:
Example:
`typescript
import { err } from 'resultage';
const errString = err('Error message');
`
Returns true if Result is OkResult, false otherwise. Narrows the Result to OkResult in "if"-branches,ErrResult
and to in "else"-branches.
Property Definition:
`typescript`
interface OkResult
interface ErrResult
Function Signature:
`typescript`
const isOk:
Example:
`typescript
import { ok } from 'resultage';
const result = ok(42);
if (result.isOk) {
console.log(result.value);
} else {
console.error(result.error);
}
`
Example with function:
`typescript
import { ok, isOk } from 'resultage';
const result = ok(42);
if (isOk(result)) {
console.log(result.value);
} else {
console.error(result.error);
}
`
The function isOk(result) is suitable for use as a callback inArray.prototype.filter or similar methods.
`typescript
import { isOk } from 'resultage';
const results = [ok(42), err('Error')];
const isEverythingOk = results.every(isOk);
`
Returns true if Result is ErrResult, false otherwise. Narrows the Result to ErrResult in "if"-branches,OkResult
and to in "else"-branches.
Property Definition:
`typescript`
interface OkResult
interface ErrResult
Function Signature:
`typescript`
const isErr:
Example:
`typescript
import { err } from 'resultage';
const result = err('Error message');
if (result.isErr) {
console.error(result.error);
} else {
console.log(result.value);
}
`
Returns true if Result is ErrResult, false otherwise. Narrows the Result to ErrResult in "if"-branches,OkResult
and to in "else"-branches.
Property Definition:
`typescript`
interface OkResult
interface ErrResult
Function Signature:
`typescript`
const isError:
Example:
`typescript
import { err } from 'resultage';
const result = err('Error message');
if (result.isError) {
console.error(result.error);
} else {
console.log(result.value);
}
`
Example with function:
`typescript
import { err, isError } from 'resultage';
const result = err('Error message');
if (isError(result)) {
console.error(result.error);
} else {
console.log(result.value);
}
`
The function isError(result) is suitable for use as a callback inArray.prototype.filter or similar methods.
`typescript
import { isError } from 'resultage';
const results = [ok(42), err('Error')];
const isSomethingWrong = results.some(isError);
`
Returns the value of OkResult. Could be accessed if and only if the ResultOkResult
is explicitly narrowed to .
Property Definition:
`typescript`
interface OkResult
Example:
`typescript
import { ok } from 'resultage';
const result = ok(42);
console.log(result.value); // Prints to console: 42
`
Example with narrowing:
`typescript
import { ok, err } from 'resultage';
const okIfOdd = (value: number) =>
value % 2 === 1
? ok(value)
: err('Value is not odd');
const result = okIfOdd(43);
result.value;
// ^^^^^ - Error: Property 'value' does not exist on type 'Result
if (result.isOk) {
console.log(result.value);
} else {
console.error(result.error);
}
`
Returns the error of ErrResult. Could be accessed if and only if the ResultErrResult
is explicitly narrowed to .
Property Definition:
`typescript`
interface ErrResult
Example:
`typescript
import { err } from 'resultage';
const result = err('Error message');
console.log(result.error); // Prints to console: Error message
`
Example with narrowing:
`typescript
import { ok, err } from 'resultage';
const okIfOdd = (value: number) =>
value % 2 === 1
? ok(value)
: err('Value is not odd');
const result = okIfOdd(42);
result.error;
// ^^^^^ - Error: Property 'error' does not exist on type 'Result
if (result.isError) {
console.error(result.error);
} else {
console.log(result.value);
}
`
Applies fn to the value of OkResult and returns the value wrapped in OkResult. If Result is ErrResult returns itself without applying fn.
Method Signature:
`typescript`
interface Result
map(fn: (data: T) => S): Result
}
Curried Function Signature:
`typescript`
const map:
Example:
`typescript
import { ok } from 'resultage';
const result = ok(42);
const mappedResult = result.map(value => value * 2);
console.log(mappedResult.value); // Prints to console: 84
`
Applies fn to the value of ErrResult and returns the value wrapped in ErrResult. If Result is OkResult returns itself without applying fn.
Method Signature:
`typescript`
interface Result
mapErr
}
Curried Function Signature:
`typescript`
const mapErr:
Example:
`typescript
import { err } from 'resultage';
const result = err('Error message');
const mappedResult = result.mapErr(error => new Error(error));
`
Applies next to the value of OkResult and returns the result of next. If the Result is ErrResult,next
returns itself without applying .
The next function must return a Result.
Method Signature:
`typescript`
interface Result
chain(next: (data: T) => Result): Result
}
Curried Function Signature:
`typescript`
const chain:
) =>
Example:
`typescript
import { ok } from 'resultage';
const result = ok(42);
const chainedResult = result.chain(value => ok(value * 2));
`
The chain method is the primary method for composing (...) => Result functions.
Applies next to the value of ErrResult and returns the result of next.Result
If the is OkResult, returns itself without applying next.
The next function must return a Result.
Method Signature:
`typescript`
interface Result
chainErr(next: (error: E) => Result): Result
}
Curried Function Signature:
`typescript`
const chainErr:
(next: (error: E) => Result) =>
Example:
`typescript
import { err } from 'resultage';
const result = err('Error message');
const chainedResult = result.chainErr(error => err(new Error(error)));
`
chainErr is a convenient method for recovering from an error.
`typescript
import { err, ok } from 'resultage';
const okIfOdd = (value: number) =>
value % 2 === 1
? ok(value)
: err('Value is not odd');
const getOdd = (value: number): number =>
okIfOdd(value)
.chainErr(() => ok(value + 1))
.unwrap();
console.log(getOdd(1)); // 1
`
Returns the value of OkResult. If the Result is ErrResult throws an Errorcause
where is the result.
Method Signature:
`typescript`
interface Result
unwrap(): T
}
Function Signature:
`typescript`
const unwrap:
Example:
`typescript
import { ok } from 'resultage';
const result = ok(42);
console.log(result.unwrap()); // Prints to console: 42
`
Example with error:
`typescript
import { err } from 'resultage';
const result = err('Error message');
console.log(result.unwrap());
// Throws an Error with the message: 'Result is not an Ok' and cause equal
// to the result.
`
Returns the value of OkResult. If the Result is ErrResult returns fallback.
Method Signature:
`typescript`
interface Result
unwrapOr(fallback: S): T | S
}
Curried Function Signature:
`typescript`
const unwrapOr:
(result: Result
Returns the value of OkResult. If the Result is ErrResult throws a value ofE
type .
unwrapOrThrow doesn't check if E is an instance of Error or not, so it is
possible to throw a non-error literal.
Method Signature:
`typescript`
interface Result
unwrapOrThrow(): T
}
Function Signature:
`typescript`
const unwrapOrThrow:
Returns the value of OkResult. If the Result is ErrResult returns the result of fallbackFn.
Method Signature:
`typescript`
interface Result
unwrapOrElse(fallbackFn: (error: E) => S): T | S
}
Curried Function Signature:
`typescript`
const unwrapOrElse:
(result: Result
Returns the value of ErrResult. If the Result is OkResult throws an Error where cause is the OkResult.
Method Signature:
`typescript`
interface Result
unwrapErr(): E
}
Function Signature:
`typescript`
const unwrapErr:
Returns the value of ErrResult. If the Result is OkResult returns fallback.
Method Signature:
`typescript`
interface Result
unwrapErrOr
}
Curried Function Signature:
`typescript`
const unwrapErrOr:
Returns the value of ErrResult. If the Result is OkResult returns the result of fallback.
Method Signature:
`typescript`
interface Result
unwrapErrOrElse
}
Curried Function Signature:
`typescript`
const unwrapErrOrElse:
Returns the value of OkResult or ErrResult.
Method Signature:
`typescript`
interface Result
unpack(): T | E
}
Function Signature:
`typescript`
const unpack:
Applies okMatcher to the value of OkResult and returns the result. Applies errMatcher to the value of ErrResult and returns the result.
Method Signature:
`typescript`
interface Result
match(okMatcher: (data: T) => S, errMatcher: (error: E) => F): S | F
}
Curried Function Signature:
`typescript`
const match:
(result: Result
Applies fn to the value of OkResult and returns the original result. If the Result is ErrResult doesn't apply fn.
Method Signature:
`typescript`
interface Result
tap(fn: (data: T) => void): Result
}
Curried Function Signature:
`typescript`
const tap:
Applies fn to the value of ErrResult and returns the original result. If the Result is OkResult doesn't apply fn.
Method Signature:
`typescript`
interface Result
tapErr(fn: (error: E) => void): Result
}
Curried Function Signature:
`typescript`
const tapErr:
Maps both the success value and the error value. Applies okFn if the result is OkResult,errFn
or if the result is ErrResult.
Method Signature:
`typescript`
interface Result
biMap(okFn: (data: T) => S, errFn: (error: E) => F): Result
}
Curried Function Signature:
`typescript`
const biMap:
(okFn: (data: T) => S, errFn: (error: E) => F) =>
(result: Result
Chains both the success value and the error value. Applies okFn if the result is OkResult,errFn
or if the result is ErrResult. Both functions must return a Result.
Method Signature:
`typescript`
interface Result
biChain
okFn: (data: T) => Result
errFn: (error: E) => Result
): Result
}
Curried Function Signature:
`typescript`
const biChain:
okFn: (data: T) => Result
errFn: (error: E) => Result
) =>
(result: Result
Returns the result as a tuple [ok, error, value].
If strict tuple checks are enabled, this allows narrowing based on the first element.
Method Signature:
`typescript`
interface Result
asTuple(): [ok: true, error: undefined, value: T] | [ok: false, error: E, value: undefined]
}
Function Signature:
`typescript`
const asTuple:
Collects OkResult values from an array of Result and returns a Result.
Function Signature:
`typescript``
const collect: