The purpose of this library is to bring functional programming concepts to TypeScript.
npm install @wunderwerk/ts-functional
TypeScript implementation of the Result
type. Heavily inspired by Rust's implementation.
The main benefit of using the Result
type is to avoid try-catch
blocks. By utilizing TypeScripts type system a function returning a Result
type carries both the success and error value, which can be easily narrowed down to the correct type using if
statements.
A result contains either an error OR the success value.
Therefore, to successfully return a Result
type, a function must return the success value wrapped in Ok()
and the error value wrapped in Err()
.
The successful result results in the following object:
{
ok: true,
err: false,
val: {} // Whatever successful value.
// Other methods...
}
On the other hand, a error result looks as follows:
{
ok: false,
err: true,
val: {} // Whatever error value.
// Other methods...
}
The happy / unhappy path can now easily be handled by just using if-else statements, instead of try-catch blocks.
The result provides additional methods:
Returns the contained successful value, throws an Error
with the provided argument as the error message, if the result is not successful.
const result = getResultSomehow();
const successValue = result.expect('Result must be successful!');
The exact opposite to expect
. Returns the contained error value, throws an Error
with the provided argument as the error message, if the result is successful.
const result = getResultSomehow();
const successValue = result.expectErr('Result must fail');
Same as expect
, except without the ability to provide a custom error message.
const result = getResultSomehow();
const successValue = result.unwrap();
Returns the contained successful value, or the provided Or
value, if the result is not successful.
const result = getResultSomehow();
const successValueOrDefault = result.unwrapOr('this is the fallback value');
Wraps the given function in a try-catch block and returns the successful value as Ok
and the catched error as Err
.
import { wrap } from "@wunderwerk/ts-functional/results";
// isEven now returns a result.
const isEven = wrap((input: number) => {
if (input % 2 === 0) {
return true;
}
throw new Error('input is not even!');
});
const result = isEven(2);
Same as wrap
but awaits the given function and returns the result in a promise.
import { wrapAsync } from "@wunderwerk/ts-functional/results";
// fetchData now returns a promise with a result.
const fetchData = wrapAsync(async () => {
const response = await fetch('https://my-api.com');
return await response.json();
});
const result = await fetchData();
Fetching data
import { Result, Ok, Err, wrapAsync } from "@wunderwerk/ts-functional/results";
interface FetchedData {
title: string;
}
const fetchSomething = wrapAsync(async () => {
const response = await fetch('https://my-api.com');
return await response.json() as FetchedData;
});
// This is effectively the same as:
// async function fetchSomething(): Result<FetchedData, Error> {
// try {
// const response = await fetch('https://my-api.com');
// const data = await response.json() as FetchedData;
//
// return Ok(data);
// } catch (e) {
// return Err(e);
// }
// }
const result = await fetchSomething();
// By checking result.err, we check if the result is an error.
// Withing the if statement, the result.val has been narrowed down to the error result.
if (result.err) {
console.error("Oh no, an error happened:", result.val.message);
return;
}
// Because the error is already handled, result.val is now the success result, meaning
// we can safely process the happy-path now.
console.log("Hurray, the fetch was successful and returned the following data:", result.val);