This cheatsheet is intended for any reader to understand and remember fp-ts' most used features.
Table of Contents
- Combining functions
- Common constructors
- Either
- Task
- TaskEither
- Bind
- What does
W
inchainW
mean? - What does
K
infromNullableK
mean? - Glossary
Definition: transform an expression in a data-first pipeline of functions.
import { pipe } from 'fp-ts/function'
const masters = ['Yoda', 'Vador', 'Luke']
pipe(
masters,
map(master => master.length),
filter(length => length > 4)
)
Definition: like pipe but data-last.
import { flow } from 'fp-ts/function'
const value = ['Yoda', 'Vador', 'Luke']
flow(
map(master => master.length),
filter(length => length > 4),
)(masters)
For all the monads that can fail below, these constructors exists
import { fromNullable } from 'fp-ts/Either'
// Without type signature
const mustExist = fromNullable(new CartMissingError())
// With explicit type signature
const mustExist: (cart: Cart | null) => Either<CartMissingError, Cart> = fromNullable(new CartMissingError())
Using a predicate
Test whether a predicate is true and return an error if not.
import { fromPredicate } from 'fp-ts/Either'
import { PropDifferentError } from '../errors'
const mustBeEqual: (obj: MyObject) => Either<PropDifferentError, MyObject> = fromPredicate(
obj => obj.prop === 'value',
obj => new PropDifferentError(obj.prop, 'value')
)
Using a refinement
Like a predicate but casts the given value into another type.
import { fromPredicate } from 'fp-ts/Either'
import { NotCartError } from '../errors'
const mustBeCart: (cartOrList: Cart | List) => Either<NotCartError, cartOrList is Cart> = fromPredicate(
cartOrList => cartOrList.type === 'cart',
cartOrList => new NotCartError()
)
Definition: an error (left) or a value (right).
interface Left<E> {
readonly _tag: 'Left'
readonly left: E
}
interface Right<A> {
readonly _tag: 'Right'
readonly right: A
}
type Either<E, A> = Left<E> | Right<A>
Return error.
function left<E = never, A = never>(e: E) => Either<E, A>
left(new Error('error'))
Return success.
function right<E = never, A = never>(a: A) => Either<E, A>
right(42)
Map the inner type to another type.
function map<A, B>(f: (a: A) => B): <E>(fa: Either<E, A>) => Either<E, B>
const either = right('string')
map(str => str.length)(either)
Chain with another Either.
function chain<E, A, B>(f: (a: A) => Either<E, B>): (ma: Either<E, A>) => Either<E, B>
pipe(
right(age),
chain(age => age < 18 ? left(new TooYoungError(age)) : right(age)
)
// With `fromPredicate`
const isOldEnough = fromPredicate(
age => age < 18,
age => new TooYoungError(age)
)
pipe(
right(age),
chain(isOldEnough)
)
You may use Either.chainW
to widen the error type.
Definition: an asynchronous computation that yields a value and never fails.
interface Task<A> {
(): Promise<A>
}
Task is often used when one destroys a TaskEither e.g.
await pipe(
useCase.execute(), // => TaskEither<E, A>
fold(
error => Task.of(error),
value => Task.of(value)
)
)()
delay(millis: number) : Creates a task that will complete after a time delay.
pipe(
T.chain(() => doSomething()),
T.chain(() => delay(1000)),
T.map(() => 'done after 1000ms')
)
Definition: an asynchronous computation that either yields a value of type A or fails, yielding an error of type E
interface TaskEither<E, A> extends Task<Either<E, A>> {}
TODO
Definition: bind allows to store a read-only context value in the composition pipeline, so that it can be reused later.
pipe(
bind('user', fromThunk(userRepository.save)),
// Here is the ContextValue
({ user }) => {
console.log(user)
}
)
// This is inferred by typescript
interface ContextValue {
readonly user: User
}
It forbids you to mutate the context value.
W
means a function is able to aggregate errors into a union (for Either based data types) or environments into an intersection (for Reader based data types).
import * as E from 'fp-ts/Either'
import * as TE from 'fp-ts/TaskEither'
import { pipe } from 'fp-ts/function'
declare function parseString(s: string): E.Either<string, number>
declare function fetchUser(id: number): TE.TaskEither<Error, User>
// This raises an error because: Type 'string' is not assignable to type 'Error'
const program_ = (s: string) => pipe(s, TE.fromEitherK(parseString), TE.chain(fetchUser))
// const program: (s: string) => TE.TaskEither<string | Error, User>
const program = (s: string) => pipe(s, TE.fromEitherK(parseString), TE.chainW(fetchUser))
K
in fromNullableK
is used to do a fromNullable
with a transformation (by a function) apply to the given agurments <A>
And then return either NonNullable<B>
or an error
export declare const fromNullableK: <E>(
e: E
) => <A extends readonly unknown[], B>(f: (...a: A) => B | null | undefined) => (...a: A) => Either<E, NonNullable<B>>
K
means Kleisli. A Kleisli arrow is a function with the following signature
(a: A) => F<B>
It's a sufix that we can find on other functions around the lib. (more info on sufix)
The value that transits throughout a pipe. See bind.
A predicate is a function with the following signature:
<A>(a: A) => boolean
A refinement is a special type of predicate that casts the given value in another type.
<A, B>(a: A) => a is B