Formulaic’s Data Types (FP)
Formulaic’s Data Types library (called "FP" for short) provides a strongly-typed and chainable data format to use as return types.
Summary
Better Visibility and Typing
When it comes to error handling, both Promise
and catch
in TypeScript hide the type of errors.
FP takes inspiration from fp-ts and other functional approaches, and uses a structure
similar to Either
from fp-ts:
import { Literal, Empty } from "@formulaic/fp";
function getData(): Literal<number> | Empty<number> {
const success: boolean = coinFlip();
return success ? new Literal(10) : new Empty();
}
Chaining
All FP classes support chaining, similar to the .then
method on Promises:
const x = new Literal(10);
const afterAddition = x.map(i => i + 10);
const afterDivision = await afterAddition.chain(async i => await Promise.resolve(i / 4));
expect(afterDivision.data).toBe(5);
Calling .then
on a rejected Promise does nothing (and keeps the value the same) -
all chaining methods from FP
do the same.
const x = new Empty<number>();
const afterAddition = x.map(i => i + 10); // => still Empty<number>, function is not called
Transformation
FP objects are easy to configure via class-transformer, and even come with some basic transformation rules built-in.
import { AccessForbidden, EntityNotFound } from "@formulaic/fp";
@Controller()
export class SampleController {
@Get("/secret")
public getSecret() {
return new AccessForbidden();
}
@Get("/misspelled-pgae")
public getUnknownEntity() {
return new EntityNotFound();
}
}
If you use a class-transformer
utility, like Formulaic’s fp-interceptor, the two routes in the example above will
produce the same 404
response to hide whether a page exists or not if the user doesn’t have permission thanks to the default class-transformer
configuration.
However, your backend (and developers, if running the server with NODE_ENV=development
) will be able to tell the two cases apart.