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.