Functional programming library for TypeScript with higher-kinded types, algebraic data types, and type classes
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The pipeable module provides modern functional programming utilities for chainable operations using the pipe function and pipeable operator style. This is the recommended modern approach for using fp-ts, offering better type inference and composition than traditional method chaining.
import { pipe } from "fp-ts/lib/pipeable";
import { pipeable } from "fp-ts/lib/pipeable";The fundamental composition function that enables left-to-right function application, replacing nested function calls with readable pipelines.
/**
* Pipe function for left-to-right function composition
* Supports up to 10 function compositions with full type safety
*/
function pipe<A>(a: A): A;
function pipe<A, B>(a: A, ab: (a: A) => B): B;
function pipe<A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C;
function pipe<A, B, C, D>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;
// ... continues up to 10 parametersUsage Examples:
import { pipe } from "fp-ts/lib/pipeable";
import { map, filter, fold } from "fp-ts/lib/Array";
import { some, none, fold as optionFold } from "fp-ts/lib/Option";
// Array processing pipeline
const result = pipe(
[1, 2, 3, 4, 5],
filter((n: number) => n > 2),
map((n: number) => n * 2),
fold(0, (acc: number, n: number) => acc + n)
);
// Result: 18
// Option processing pipeline
const maybeDouble = pipe(
some(21),
map((n: number) => n * 2),
optionFold(
() => "No value",
(value: number) => `Value: ${value}`
)
);
// Result: "Value: 42"Type-safe interfaces that provide pipeable versions of common functional operations for all data types that support them.
interface PipeableFunctor<F> {
readonly map: <A, B>(f: (a: A) => B) => (fa: HKT<F, A>) => HKT<F, B>;
}
interface PipeableFunctor1<F extends URIS> {
readonly map: <A, B>(f: (a: A) => B) => (fa: Kind<F, A>) => Kind<F, B>;
}
interface PipeableFunctor2<F extends URIS2> {
readonly map: <A, B>(f: (a: A) => B) => <L>(fa: Kind2<F, L, A>) => Kind2<F, L, B>;
}interface PipeableApply<F> extends PipeableFunctor<F> {
readonly ap: <A>(fa: HKT<F, A>) => <B>(fab: HKT<F, (a: A) => B>) => HKT<F, B>;
readonly apFirst: <B>(fb: HKT<F, B>) => <A>(fa: HKT<F, A>) => HKT<F, A>;
readonly apSecond: <B>(fb: HKT<F, B>) => <A>(fa: HKT<F, A>) => HKT<F, B>;
}interface PipeableChain<F> extends PipeableApply<F> {
readonly chain: <A, B>(f: (a: A) => HKT<F, B>) => (ma: HKT<F, A>) => HKT<F, B>;
readonly chainFirst: <A, B>(f: (a: A) => HKT<F, B>) => (ma: HKT<F, A>) => HKT<F, A>;
readonly flatten: <A>(mma: HKT<F, HKT<F, A>>) => HKT<F, A>;
}interface PipeableFoldable<F> {
readonly reduce: <A, B>(b: B, f: (b: B, a: A) => B) => (fa: HKT<F, A>) => B;
readonly foldMap: <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: HKT<F, A>) => M;
readonly reduceRight: <A, B>(b: B, f: (a: A, b: B) => B) => (fa: HKT<F, A>) => B;
}interface PipeableFilterable<F> extends PipeableCompactable<F> {
readonly filter: {
<A, B extends A>(refinement: Refinement<A, B>): (fa: HKT<F, A>) => HKT<F, B>;
<A>(predicate: Predicate<A>): (fa: HKT<F, A>) => HKT<F, A>;
};
readonly filterMap: <A, B>(f: (a: A) => Option<B>) => (fa: HKT<F, A>) => HKT<F, B>;
readonly partition: {
<A, B extends A>(refinement: Refinement<A, B>): (fa: HKT<F, A>) => Separated<HKT<F, A>, HKT<F, B>>;
<A>(predicate: Predicate<A>): (fa: HKT<F, A>) => Separated<HKT<F, A>, HKT<F, A>>;
};
readonly partitionMap: <A, RL, RR>(
f: (a: A) => Either<RL, RR>
) => (fa: HKT<F, A>) => Separated<HKT<F, RL>, HKT<F, RR>>;
}Creates pipeable operators from type class instances, enabling the modern functional style for any data type.
/**
* Creates pipeable operators from a type class instance
* Automatically detects available operations and generates appropriate pipeable functions
*/
function pipeable<F extends URIS4, I>(
I: { URI: F } & I
): PipeableChain4<F> & PipeableApply4<F> & PipeableFunctor4<F> & /* ... other interfaces based on I */;
function pipeable<F extends URIS3, I>(
I: { URI: F } & I
): PipeableChain3<F> & PipeableApply3<F> & PipeableFunctor3<F> & /* ... other interfaces based on I */;
function pipeable<F extends URIS2, I>(
I: { URI: F } & I
): PipeableChain2<F> & PipeableApply2<F> & PipeableFunctor2<F> & /* ... other interfaces based on I */;
function pipeable<F extends URIS, I>(
I: { URI: F } & I
): PipeableChain1<F> & PipeableApply1<F> & PipeableFunctor1<F> & /* ... other interfaces based on I */;Usage Examples:
import { pipeable } from "fp-ts/lib/pipeable";
import { option } from "fp-ts/lib/Option";
import { either } from "fp-ts/lib/Either";
import { array } from "fp-ts/lib/Array";
// Create pipeable operators for Option
const { map, chain, filter } = pipeable(option);
// Create pipeable operators for Either
const { map: mapE, mapLeft, bimap } = pipeable(either);
// Create pipeable operators for Array
const { map: mapA, filter: filterA, fold } = pipeable(array);
// Use in pipelines
pipe(
some(42),
map((n: number) => n * 2),
chain((n: number) => n > 50 ? some(n) : none),
filter((n: number) => n % 2 === 0)
);interface PipeableBifunctor<F> {
readonly bimap: <L, A, M, B>(f: (l: L) => M, g: (a: A) => B) => (fa: HKT2<F, L, A>) => HKT2<F, M, B>;
readonly mapLeft: <L, M>(f: (l: L) => M) => <A>(fa: HKT2<F, L, A>) => HKT2<F, M, A>;
}interface PipeableContravariant<F> {
readonly contramap: <A, B>(f: (b: B) => A) => (fa: HKT<F, A>) => HKT<F, B>;
}interface PipeableMonadThrow<F> {
readonly fromOption: <E>(onNone: () => E) => <A>(ma: Option<A>) => HKT<F, A>;
readonly fromEither: <E, A>(ma: Either<E, A>) => HKT<F, A>;
readonly fromPredicate: {
<E, A, B extends A>(refinement: Refinement<A, B>, onFalse: (a: A) => E): (a: A) => HKT<F, B>;
<E, A>(predicate: Predicate<A>, onFalse: (a: A) => E): (a: A) => HKT<F, A>;
};
readonly filterOrElse: {
<E, A, B extends A>(refinement: Refinement<A, B>, onFalse: (a: A) => E): (ma: HKT<F, A>) => HKT<F, B>;
<E, A>(predicate: Predicate<A>, onFalse: (a: A) => E): (ma: HKT<F, A>) => HKT<F, A>;
};
}All pipeable interfaces come in multiple variants to support fp-ts's Higher Kinded Types system:
// For HKT (generic)
interface PipeableFunctor<F> { /* ... */ }
// For URIS (single type parameter)
interface PipeableFunctor1<F extends URIS> { /* ... */ }
// For URIS2 (two type parameters)
interface PipeableFunctor2<F extends URIS2> { /* ... */ }
// For URIS2C (two type parameters, first constrained)
interface PipeableFunctor2C<F extends URIS2, L> { /* ... */ }
// For URIS3 (three type parameters)
interface PipeableFunctor3<F extends URIS3> { /* ... */ }
// For URIS4 (four type parameters)
interface PipeableFunctor4<F extends URIS4> { /* ... */ }import { pipe } from "fp-ts/lib/pipeable";
import { some, none, map, chain, fold } from "fp-ts/lib/Option";
const processValue = (input: number) => pipe(
some(input),
map((n: number) => n * 2),
chain((n: number) => n > 10 ? some(n) : none),
fold(
() => "Value too small",
(n: number) => `Processed value: ${n}`
)
);import { pipe } from "fp-ts/lib/pipeable";
import { left, right, map, mapLeft, fold } from "fp-ts/lib/Either";
const parseAndDouble = (input: string) => pipe(
parseInt(input, 10),
(n: number) => isNaN(n) ? left("Invalid number") : right(n),
map((n: number) => n * 2),
mapLeft((error: string) => `Parse error: ${error}`),
fold(
(error: string) => ({ success: false, error }),
(value: number) => ({ success: true, value })
)
);import { pipe } from "fp-ts/lib/pipeable";
import { map, filter, fold } from "fp-ts/lib/Array";
const processNumbers = (numbers: number[]) => pipe(
numbers,
filter((n: number) => n > 0),
map((n: number) => n * n),
fold(0, (acc: number, n: number) => acc + n)
);// Higher Kinded Types support
import { HKT, HKT2, Kind, Kind2, Kind3, Kind4, URIS, URIS2, URIS3, URIS4 } from './HKT';
// Supporting types
import { Predicate, Refinement } from './function';
import { Option } from './Option';
import { Either } from './Either';
import { Separated } from './Compactable';
import { Monoid } from './Monoid';