Core functional programming primitives including pipe operator, function composition, identity functions, and type utilities for building composable data transformations and functional programming patterns.
Functions for composing and chaining operations together in a functional programming style.
/**
* The pipe function allows for composing functions in a left-to-right manner
* Each function receives the output of the previous function as input
*/
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;
function pipe<A, B, C, D, E>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E
): E;
// ... additional overloads up to 20 arguments
/**
* Creates a new function by composing functions from left to right
* The first function can accept multiple arguments
*/
function flow<A extends ReadonlyArray<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;
function flow<A extends ReadonlyArray<unknown>, B, C>(
ab: (...a: A) => B,
bc: (b: B) => C
): (...a: A) => C;
function flow<A extends ReadonlyArray<unknown>, B, C, D>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D
): (...a: A) => D;
// ... additional overloads up to 20 functions
/**
* Function composition from right to left (reverse of flow)
*/
function compose<A, B>(ab: (a: A) => B): (a: A) => B;
function compose<A, B, C>(bc: (b: B) => C, ab: (a: A) => B): (a: A) => C;
function compose<A, B, C, D>(cd: (c: C) => D, bc: (b: B) => C, ab: (a: A) => B): (a: A) => D;
// ... additional overloadsUsage Examples:
import { pipe, flow } from "effect";
// Pipe for data transformation
const result = pipe(
"hello world",
(s) => s.toUpperCase(),
(s) => s.split(" "),
(arr) => arr.join("-")
); // "HELLO-WORLD"
// Flow for creating reusable function pipelines
const processString = flow(
(s: string) => s.trim(),
(s) => s.toLowerCase(),
(s) => s.replace(/\s+/g, "-")
);
const slug = processString(" Hello World "); // "hello-world"
// Complex data processing
const processUser = flow(
(raw: { name: string; age: string; email: string }) => ({
name: raw.name.trim(),
age: parseInt(raw.age),
email: raw.email.toLowerCase()
}),
(user) => ({
...user,
isAdult: user.age >= 18,
domain: user.email.split("@")[1]
})
);Essential utility functions for functional programming including identity, constants, and type utilities.
/**
* The identity function - returns its argument unchanged
*/
function identity<A>(a: A): A;
/**
* Creates a constant function that always returns the same value
*/
function constant<A>(value: A): LazyArg<A>;
/**
* Constant functions for common values
*/
const constTrue: LazyArg<boolean>;
const constFalse: LazyArg<boolean>;
const constNull: LazyArg<null>;
const constUndefined: LazyArg<undefined>;
const constVoid: LazyArg<void>;
/**
* Flips the order of arguments for a binary function
*/
function flip<A, B, C>(f: (a: A, b: B) => C): (b: B, a: A) => C;
/**
* Function application - applies a function to a value
*/
function apply<A>(a: A): <B>(f: (a: A) => B) => B;
/**
* Handles impossible cases (never type)
*/
function absurd<A>(_: never): A;
/**
* Type hole for incomplete implementations
*/
function hole<T>(): T;
/**
* Unsafe type coercion (use with caution)
*/
function unsafeCoerce<A, B>(a: A): B;Usage Examples:
import { identity, constant, flip, apply } from "effect";
// Identity function
const numbers = [1, 2, 3].map(identity); // [1, 2, 3]
// Constant functions
const alwaysTrue = constant(true);
console.log(alwaysTrue()); // true
const users = ["alice", "bob"].map(() => constant("anonymous")());
// ["anonymous", "anonymous"]
// Flip argument order
const subtract = (a: number, b: number): number => a - b;
const subtractFlipped = flip(subtract);
console.log(subtract(10, 3)); // 7
console.log(subtractFlipped(3, 10)); // 7
// Function application in pipelines
const result = pipe(
42,
apply((n: number) => n * 2)
); // 84Functions for working with tuples and converting between tupled and curried forms.
/**
* Converts a function that takes multiple arguments into one that takes a tuple
*/
function tupled<A extends ReadonlyArray<unknown>, B>(f: (...a: A) => B): (a: A) => B;
/**
* Converts a function that takes a tuple into one that takes multiple arguments
*/
function untupled<A extends ReadonlyArray<unknown>, B>(f: (a: A) => B): (...a: A) => B;Usage Examples:
import { tupled, untupled } from "effect";
// Convert to tupled form
const add = (a: number, b: number): number => a + b;
const addTupled = tupled(add);
console.log(add(2, 3)); // 5
console.log(addTupled([2, 3])); // 5
// Convert from tupled form
const multiplyTupled = ([a, b]: [number, number]): number => a * b;
const multiply = untupled(multiplyTupled);
console.log(multiplyTupled([4, 5])); // 20
console.log(multiply(4, 5)); // 20
// Useful with array operations
const pairs: Array<[number, number]> = [[1, 2], [3, 4], [5, 6]];
const sums = pairs.map(addTupled); // [3, 7, 11]Functions that support both data-first and data-last (curried) calling styles.
/**
* Creates a dual-style function that can be called in both data-first and data-last style
*/
function dual<DataFirst extends (...args: Array<any>) => any, DataLast extends (...args: Array<any>) => any>(
arity: Parameters<DataFirst>["length"],
body: DataFirst
): DataLast & DataFirst;Usage Examples:
import { dual, pipe } from "effect";
// Create a dual-style map function
const map = dual<
<A, B>(self: ReadonlyArray<A>, f: (a: A) => B) => ReadonlyArray<B>,
<A, B>(f: (a: A) => B) => (self: ReadonlyArray<A>) => ReadonlyArray<B>
>(2, (self, f) => self.map(f));
// Data-first style
const numbers1 = map([1, 2, 3], x => x * 2); // [2, 4, 6]
// Data-last style (pipe-friendly)
const numbers2 = pipe(
[1, 2, 3],
map(x => x * 2)
); // [2, 4, 6]
// Another example: filter function
const filter = dual<
<A>(self: ReadonlyArray<A>, predicate: (a: A) => boolean) => ReadonlyArray<A>,
<A>(predicate: (a: A) => boolean) => (self: ReadonlyArray<A>) => ReadonlyArray<A>
>(2, (self, predicate) => self.filter(predicate));
const evens = pipe(
[1, 2, 3, 4, 5],
filter(x => x % 2 === 0)
); // [2, 4]Functions for type-level operations and satisfying TypeScript's type system.
/**
* A function that takes a value and ensures it satisfies a type constraint
* Returns the value unchanged but with type-level verification
*/
function satisfies<A>(): <B extends A>(b: B) => B;
/**
* Type-level function representation for higher-kinded types
*/
interface FunctionTypeLambda extends TypeLambda {
readonly type: (a: this["Target"]) => this["Return"];
}
/**
* Function type alias
*/
type FunctionN<A, B> = (a: A) => B;Usage Examples:
import { satisfies } from "effect";
// Type constraint satisfaction
interface User {
id: number;
name: string;
}
const createUser = satisfies<User>()({
id: 1,
name: "Alice",
email: "alice@example.com" // Extra properties are preserved
});
// Ensuring configuration objects match interfaces
interface Config {
apiUrl: string;
timeout: number;
}
const config = satisfies<Config>()({
apiUrl: "https://api.example.com",
timeout: 5000,
debug: true // Extra property allowed
});Time duration operations with support for various time units and arithmetic.
interface Duration extends Pipeable {
readonly _tag: "Duration";
readonly value: DurationValue;
}
declare namespace Duration {
/**
* Creates duration from milliseconds
*/
function millis(ms: number): Duration;
/**
* Creates duration from seconds
*/
function seconds(s: number): Duration;
/**
* Creates duration from minutes
*/
function minutes(m: number): Duration;
/**
* Creates duration from hours
*/
function hours(h: number): Duration;
/**
* Creates duration from days
*/
function days(d: number): Duration;
/**
* Adds two durations
*/
function sum(that: Duration): (self: Duration) => Duration;
/**
* Converts duration to milliseconds
*/
function toMillis(self: Duration): number;
/**
* Converts duration to seconds
*/
function toSeconds(self: Duration): number;
/**
* Checks if duration is zero
*/
function isZero(self: Duration): boolean;
/**
* Infinite duration
*/
const infinity: Duration;
}Enhanced string operations with functional programming patterns.
declare namespace String {
/**
* Checks if string is empty
*/
function isEmpty(self: string): boolean;
/**
* Checks if string is non-empty
*/
function isNonEmpty(self: string): boolean;
/**
* Gets string length
*/
function length(self: string): number;
/**
* Trims whitespace
*/
function trim(self: string): string;
/**
* Converts to uppercase
*/
function toUpperCase(self: string): string;
/**
* Converts to lowercase
*/
function toLowerCase(self: string): string;
/**
* Splits string by separator
*/
function split(separator: string): (self: string) => string[];
/**
* Joins array of strings
*/
function join(separator: string): (self: ReadonlyArray<string>) => string;
/**
* Replaces occurrences
*/
function replace(searchValue: string | RegExp, replaceValue: string): (self: string) => string;
/**
* Checks if string starts with prefix
*/
function startsWith(prefix: string): (self: string) => boolean;
/**
* Checks if string ends with suffix
*/
function endsWith(suffix: string): (self: string) => boolean;
/**
* Checks if string includes substring
*/
function includes(searchString: string): (self: string) => boolean;
}Mathematical operations and number utilities with functional patterns.
declare namespace Number {
/**
* Checks if number is NaN
*/
function isNaN(self: number): boolean;
/**
* Checks if number is finite
*/
function isFinite(self: number): boolean;
/**
* Checks if number is integer
*/
function isInteger(self: number): boolean;
/**
* Checks if number is safe integer
*/
function isSafeInteger(self: number): boolean;
/**
* Converts to integer (truncates)
*/
function toInteger(self: number): number;
/**
* Rounds to nearest integer
*/
function round(self: number): number;
/**
* Rounds down
*/
function floor(self: number): number;
/**
* Rounds up
*/
function ceil(self: number): number;
/**
* Gets absolute value
*/
function abs(self: number): number;
/**
* Clamps number between min and max
*/
function clamp(min: number, max: number): (self: number) => number;
/**
* Adds two numbers
*/
function sum(that: number): (self: number) => number;
/**
* Multiplies two numbers
*/
function multiply(that: number): (self: number) => number;
/**
* Divides two numbers
*/
function divide(that: number): (self: number) => number;
/**
* Subtracts two numbers
*/
function subtract(that: number): (self: number) => number;
}// Lazy argument type for deferred computation
type LazyArg<A> = () => A;
// Function type with multiple parameters
type FunctionN<A extends ReadonlyArray<unknown>, B> = (...args: A) => B;
// Higher-kinded type for functions
interface FunctionTypeLambda extends TypeLambda {
readonly type: (a: this["Target"]) => this["Return"];
}
// Type lambda base interface
interface TypeLambda {
readonly Target: unknown;
readonly Return: unknown;
}
// Duration value types
type DurationValue =
| { readonly _tag: "Millis"; readonly millis: number }
| { readonly _tag: "Infinity" };
type DurationInput =
| Duration
| number
| bigint
| { readonly millis: number }
| { readonly seconds: number }
| { readonly minutes: number }
| { readonly hours: number }
| { readonly days: number };