CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-fp-ts

Functional programming library for TypeScript with higher-kinded types, algebraic data types, and type classes

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

type-classes.mddocs/

Type Classes

Type classes in fp-ts provide generic operations that work across different data types. They enable higher-level abstractions and code reuse through polymorphism, similar to interfaces but more powerful.

Capabilities

Functor

Map functions over wrapped values, preserving structure.

interface Functor<F> {
  readonly map: <A, B>(fa: HKT<F, A>, f: (a: A) => B) => HKT<F, B>;
}

interface Functor1<F extends URIS> {
  readonly map: <A, B>(fa: Kind<F, A>, f: (a: A) => B) => Kind<F, B>;
}

interface Functor2<F extends URIS2> {
  readonly map: <L, A, B>(fa: Kind2<F, L, A>, f: (a: A) => B) => Kind2<F, L, B>;
}

Usage Examples:

import { map } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Map over Option
const doubled = map((n: number) => n * 2)(some(21)); // Some(42)
const stillNone = map((n: number) => n * 2)(none);   // None

Apply

Apply wrapped functions to wrapped values.

interface Apply<F> extends Functor<F> {
  readonly ap: <A, B>(fab: HKT<F, (a: A) => B>, fa: HKT<F, A>) => HKT<F, B>;
}

interface Apply1<F extends URIS> extends Functor1<F> {
  readonly ap: <A, B>(fab: Kind<F, (a: A) => B>, fa: Kind<F, A>) => Kind<F, B>;
}

interface Apply2<F extends URIS2> extends Functor2<F> {
  readonly ap: <L, A, B>(fab: Kind2<F, L, (a: A) => B>, fa: Kind2<F, L, A>) => Kind2<F, L, B>;
}

Applicative

Lift pure values into wrapped context, extending Apply.

interface Applicative<F> extends Apply<F> {
  readonly of: <A>(a: A) => HKT<F, A>;
}

interface Applicative1<F extends URIS> extends Apply1<F> {
  readonly of: <A>(a: A) => Kind<F, A>;
}

interface Applicative2<F extends URIS2> extends Apply2<F> {
  readonly of: <L, A>(a: A) => Kind2<F, L, A>;
}

Usage Examples:

import { sequenceS } from "fp-ts/lib/Apply";
import { option } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Combine multiple Options
const result = sequenceS(option)({
  name: some("Alice"),
  age: some(30),
  email: some("alice@example.com")
});
// Some({ name: "Alice", age: 30, email: "alice@example.com" })

// If any is None, result is None
const failed = sequenceS(option)({
  name: some("Bob"),
  age: none,
  email: some("bob@example.com")
});
// None

Chain

Sequential composition of wrapped computations (also known as flatMap).

interface Chain<F> extends Apply<F> {
  readonly chain: <A, B>(fa: HKT<F, A>, f: (a: A) => HKT<F, B>) => HKT<F, B>;
}

interface Chain1<F extends URIS> extends Apply1<F> {
  readonly chain: <A, B>(fa: Kind<F, A>, f: (a: A) => Kind<F, B>) => Kind<F, B>;
}

interface Chain2<F extends URIS2> extends Apply2<F> {
  readonly chain: <L, A, B>(fa: Kind2<F, L, A>, f: (a: A) => Kind2<F, L, B>) => Kind2<F, L, B>;
}

Monad

Combines Applicative and Chain, enabling full monadic operations.

interface Monad<F> extends Applicative<F>, Chain<F> {}

interface Monad1<F extends URIS> extends Applicative1<F>, Chain1<F> {}

interface Monad2<F extends URIS2> extends Applicative2<F>, Chain2<F> {}

Usage Examples:

import { chain, of } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Chain optional computations
const divide = (n: number) => (d: number) => 
  d === 0 ? none : some(n / d);

const result1 = chain(divide(10))(some(2)); // Some(5)
const result2 = chain(divide(10))(some(0)); // None
const result3 = chain(divide(10))(none);    // None

Foldable

Fold (reduce) structures to single values.

interface Foldable<F> {
  readonly reduce: <A, B>(fa: HKT<F, A>, b: B, f: (b: B, a: A) => B) => B;
  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: HKT<F, A>, f: (a: A) => M) => M;
  readonly reduceRight: <A, B>(fa: HKT<F, A>, b: B, f: (a: A, b: B) => B) => B;
}

interface Foldable1<F extends URIS> {
  readonly reduce: <A, B>(fa: Kind<F, A>, b: B, f: (b: B, a: A) => B) => B;
  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: Kind<F, A>, f: (a: A) => M) => M;
  readonly reduceRight: <A, B>(fa: Kind<F, A>, b: B, f: (a: A, b: B) => B) => B;
}

Usage Examples:

import { reduce, foldMap } from "fp-ts/lib/Array";
import { monoidSum } from "fp-ts/lib/Monoid";

// Reduce array to sum
const numbers = [1, 2, 3, 4, 5];
const sum = reduce(0, (acc: number, n: number) => acc + n)(numbers); // 15

// Fold with monoid
const total = foldMap(monoidSum)((n: number) => n)(numbers); // 15

Traversable

Traverse structures, applying effects while preserving shape.

interface Traversable<F> extends Functor<F>, Foldable<F> {
  readonly traverse: <G>(G: Applicative<G>) => <A, B>(ta: HKT<F, A>, f: (a: A) => HKT<G, B>) => HKT<G, HKT<F, B>>;
  readonly sequence: <G>(G: Applicative<G>) => <A>(tga: HKT<F, HKT<G, A>>) => HKT<G, HKT<F, A>>;
}

Usage Examples:

import { traverse } from "fp-ts/lib/Array";
import { option } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Transform array of numbers to array of Options, then sequence
const parseInts = (strings: string[]) => 
  traverse(option)(strings, (s: string) => {
    const n = parseInt(s, 10);
    return isNaN(n) ? none : some(n);
  });

const valid = parseInts(["1", "2", "3"]);    // Some([1, 2, 3])
const invalid = parseInts(["1", "a", "3"]);  // None

Semigroup

Associative binary operation for combining values.

interface Semigroup<A> {
  readonly concat: (x: A, y: A) => A;
}

Usage Examples:

import { semigroupSum, semigroupString } from "fp-ts/lib/Semigroup";

// Numeric addition
const sum = semigroupSum.concat(5, 10); // 15

// String concatenation
const greeting = semigroupString.concat("Hello", " World"); // "Hello World"

// Custom semigroup
const semigroupMax: Semigroup<number> = {
  concat: (x, y) => Math.max(x, y)
};
const maximum = semigroupMax.concat(3, 7); // 7

Monoid

Semigroup with identity element.

interface Monoid<A> extends Semigroup<A> {
  readonly empty: A;
}

Usage Examples:

import { monoidSum, monoidString, fold } from "fp-ts/lib/Monoid";

// Identity elements
const zeroSum = monoidSum.empty;     // 0
const emptyString = monoidString.empty; // ""

// Fold array with monoid
const numbers = [1, 2, 3, 4, 5];
const total = fold(monoidSum)(numbers); // 15

const words = ["Hello", " ", "World"];
const sentence = fold(monoidString)(words); // "Hello World"

Eq

Equality testing type class.

interface Eq<A> {
  readonly equals: (x: A, y: A) => boolean;
}

Usage Examples:

import { eqNumber, eqString, contramap } from "fp-ts/lib/Eq";

// Basic equality
const isEqual = eqNumber.equals(5, 5); // true
const notEqual = eqString.equals("a", "b"); // false

// Derive equality for complex types
interface Person {
  name: string;
  age: number;
}

const eqPerson: Eq<Person> = {
  equals: (x, y) => x.name === y.name && x.age === y.age
};

// Use contramap to derive from existing Eq
const eqPersonByName = contramap((p: Person) => p.name)(eqString);

Ord

Ordering/comparison type class.

interface Ord<A> extends Eq<A> {
  readonly compare: (x: A, y: A) => Ordering;
}

type Ordering = -1 | 0 | 1;

Usage Examples:

import { ordNumber, ordString, min, max, sort } from "fp-ts/lib/Ord";

// Comparison
const comparison = ordNumber.compare(5, 10); // -1 (less than)

// Min/max
const minimum = min(ordNumber)(3, 7); // 3
const maximum = max(ordString)("apple", "banana"); // "banana"

// Sort array
const numbers = [3, 1, 4, 1, 5];
const sorted = sort(ordNumber)(numbers); // [1, 1, 3, 4, 5]

Show

String representation type class.

interface Show<A> {
  readonly show: (a: A) => string;
}

Usage Examples:

import { showNumber, showString, showBoolean } from "fp-ts/lib/Show";

// Basic show instances
const numStr = showNumber.show(42);        // "42"
const strStr = showString.show("hello");   // "hello"
const boolStr = showBoolean.show(true);    // "true"

// Custom show instance
interface Person {
  name: string;
  age: number;
}

const showPerson: Show<Person> = {
  show: (p) => `${p.name} (${p.age})`
};

const personStr = showPerson.show({ name: "Alice", age: 30 }); // "Alice (30)"

Alternative

Choice between alternatives with identity.

interface Alternative<F> extends Applicative<F>, Plus<F> {}

interface Plus<F> extends Alt<F> {
  readonly zero: <A>() => HKT<F, A>;
}

interface Alt<F> extends Functor<F> {
  readonly alt: <A>(fx: HKT<F, A>, fy: Lazy<HKT<F, A>>) => HKT<F, A>;
}

Usage Examples:

import { alt } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Alternative choices
const first = alt(() => some("fallback"))(some("primary"));   // Some("primary")
const second = alt(() => some("fallback"))(none);             // Some("fallback")
const third = alt(() => none)(none);                          // None

Higher-Order Operations

Generic operations that work with any type class instance.

/**
 * Sequence array of wrapped values
 * @param A - Applicative instance
 * @returns Function that sequences array
 */
function sequenceArray<F extends URIS>(A: Applicative1<F>): <A>(arr: Array<Kind<F, A>>) => Kind<F, Array<A>>;

/**
 * Traverse array with effect
 * @param A - Applicative instance
 * @returns Function that traverses array
 */
function traverseArray<F extends URIS>(A: Applicative1<F>): <A, B>(f: (a: A) => Kind<F, B>) => (arr: Array<A>) => Kind<F, Array<B>>;

/**
 * Replicate wrapped value n times
 * @param A - Applicative instance
 * @returns Function that replicates value
 */
function replicateA<F extends URIS>(A: Applicative1<F>): <A>(n: number, fa: Kind<F, A>) => Kind<F, Array<A>>;

docs

algebraic.md

array.md

either.md

function.md

index.md

io.md

option.md

pipeable.md

record.md

task-either.md

task.md

type-classes.md

tile.json