Skip to content
Effect Days 2026 Get your ticket

Function

Provides small helpers for defining and reusing TypeScript functions.

The main helpers are pipe and flow for left-to-right composition and dual for APIs that support both direct and pipe-friendly call styles. The module also contains small identity, constant, tuple, type-level, and memoization helpers used across the library.

25 exports Added in v2.0.0 Source

Caching

memoize

Added in v4.0.0 Source

Creates a memoized function whose input is an object, caching results by object identity.

When to use

Use to reuse the result of a synchronous computation whose output is stable for a given object reference.

Details

Each memoized wrapper owns a private WeakMap keyed by object identity.

Gotchas

undefined is reserved to represent a cache miss and is therefore not supported as a return value.

Structurally equal objects do not share cache entries. If the same object is mutated after its first call, later calls still return the cached result for that reference.

Signature

declare function memoize<A extends object, O extends {} | null>(f: (a: A) => O): (ast: A) => O

Creates a memoized idempotent object transformation that caches both inputs and their outputs by object identity.

When to use

Use when an object transformation is idempotent and its output can be safely reused as a fixed point.

Details

After computing an input, the returned function caches both the input and the output. Calling it with either reference returns the output without invoking the supplied function again.

Gotchas

The returned function treats each computed output as a fixed point. If applying the supplied function to an output would produce an observably different value, this memoization changes that behavior.

See

  • memoize for memoizing functions without an idempotence requirement

Signature

declare function memoizeIdempotent<A extends object>(f: (a: A) => A): (a: A) => A

Combinators

apply

Added in v2.0.0 Source

Applies a function to a given value.

When to use

Use to pass a fixed value into a unary function, especially when the function is the value flowing through pipe.

Details

apply(a)(f) is equivalent to f(a).

See

  • pipe for building left-to-right pipelines

Signature

declare function apply<A>(a: A): <B>(self: (a: A) => B) => B

Example

(Applying an argument to a function)

import { Function, pipe, String } from "effect"
pipe(String.length, Function.apply("hello")) // => 5

compose

Added in v2.0.0 Source

Composes two functions, ab and bc into a single function that takes in an argument a of type A and returns a result of type C. The result is obtained by first applying the ab function to a and then applying the bc function to the result of ab.

When to use

Use to compose exactly two unary functions into a reusable unary function.

See

  • flow for composing a left-to-right sequence of functions
  • pipe for applying a value through a left-to-right sequence immediately

Signature

declare const compose: {
<B, C>(bc: (b: B) => C): <A>(self: (a: A) => B) => (a: A) => C;
<A, B, C>(self: (a: A) => B, bc: (b: B) => C): (a: A) => C;
}

Example

(Composing two functions)

import { Function } from "effect"
const increment = (n: number) => n + 1
const square = (n: number) => n * n
Function.compose(increment, square)(2) // => 9

dual

Added in v2.0.0 Source

Creates a function that can be called in data-first style or data-last (pipe-friendly) style.

When to use

Use to expose one implementation through both direct and pipe-friendly call styles.

Details

Pass either the arity of the uncurried function or a predicate that decides whether the current call is data-first. Arity is the common case. Use a predicate when optional arguments make arity ambiguous.

Signature

declare const dual: {
<DataLast extends (...args: Array<any>) => any, DataFirst extends (...args: Array<any>) => any>(arity: Parameters<DataFirst>["length"], body: DataFirst): DataLast & DataFirst;
<DataLast extends (...args: Array<any>) => any, DataFirst extends (...args: Array<any>) => any>(isDataFirst: (args: IArguments) => boolean, body: DataFirst): DataLast & DataFirst;
}

Example

(Selecting data-first or data-last style by arity)

import { Function, pipe } from "effect"
const sum = Function.dual<
(that: number) => (self: number) => number,
(self: number, that: number) => number
>(2, (self, that) => self + that)
sum(2, 3) // => 5
pipe(2, sum(3)) // => 5

Example

(Defining overloads with call signatures)

import { Function, pipe } from "effect"
const sum: {
(that: number): (self: number) => number
(self: number, that: number): number
} = Function.dual(2, (self: number, that: number): number => self + that)
sum(2, 3) // => 5
pipe(2, sum(3)) // => 5

Example

(Selecting data-first or data-last style with a predicate)

import { Function, pipe } from "effect"
const sum = Function.dual<
(that: number) => (self: number) => number,
(self: number, that: number) => number
>(
(args) => args.length === 2,
(self, that) => self + that
)
sum(2, 3) // => 5
pipe(2, sum(3)) // => 5

flip

Added in v2.0.0 Source

Reverses the order of arguments for a curried function.

When to use

Use to adapt a curried function when its argument groups need to be supplied in the opposite order.

Signature

declare function flip<A extends Array<unknown>, B extends Array<unknown>, C>(f: (...a: A) => (...b: B) => C): (...b: B) => (...a: A) => C

Example

(Flipping curried arguments)

import { Function } from "effect"
const f = (a: number) => (b: string) => a - b.length
Function.flip(f)("aaa")(2) // => -1

flow

Added in v2.0.0 Source

Performs left-to-right function composition.

When to use

Use to build a reusable function from a left-to-right sequence of transformations.

Details

The first function may have any arity. Every following function must be unary.

See

  • pipe for applying a value through a left-to-right sequence immediately
  • compose for composing exactly two functions

Signature

declare function flow<A extends readonly Array<unknown>, B = never>(ab: (...a: A) => B): (...a: A) => B
declare function flow<A extends readonly Array<unknown>, B = never, C = never>(ab: (...a: A) => B, bc: (b: B) => C): (...a: A) => C
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...a: A) => D
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): (...a: A) => E
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never, F = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): (...a: A) => F
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never, F = never, G = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): (...a: A) => G
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never, F = never, G = never, H = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): (...a: A) => H
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I): (...a: A) => I
declare function flow<A extends readonly Array<unknown>, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J): (...a: A) => J

Example

(Composing functions left to right)

import { flow } from "effect"
const len = (s: string): number => s.length
const double = (n: number): number => n * 2
const f = flow(len, double)
f("aaa") // => 6

identity

Added in v2.0.0 Source

Returns its input argument unchanged.

When to use

Use to return a value unchanged where a function is required.

Signature

declare function identity<A>(a: A): A

Example

(Returning the same value)

import { identity } from "effect"
identity(5) // => 5

pipe

Added in v2.0.0 Source

Pipes the value of an expression through a left-to-right sequence of functions.

When to use

Use when you need to compose data-last functions into readable transformation pipelines instead of method-style chains.

Details

Takes an initial value, passes it to the first function, then passes each result to the next function in order. The final function result is returned.

Gotchas

Each function passed after the initial value must accept a single argument, because pipe calls each step with only the previous result.

Example (Piping values through functions)

In this example, 1 is passed to the first function, and each result becomes the input for the next function.

Example (Rewriting method chains with pipe)

The same transformation can be written with data-last functions.

Signature

declare function pipe<A>(a: A): A
declare function pipe<A, B = never>(a: A, ab: (a: A) => B): B
declare function pipe<A, B = never, C = never>(a: A, ab: (a: A) => B, bc: (b: B) => C): C
declare function pipe<A, B = never, C = never, D = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D
declare function pipe<A, B = never, C = never, D = never, E = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E
declare function pipe<A, B = never, C = never, D = never, E = never, F = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): F
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): G
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): H
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I): I
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J): J
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K): K
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L): L
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M): M
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N): N
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O): O
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P): P
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q): Q
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R): R
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S): S
declare function pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T): T

Example

(Piping values through functions)

import { pipe } from "effect"
pipe(
1,
(n) => n + 1,
(n) => n * 2,
(n) => `result: ${n}`
) // => "result: 4"

Example

(Rewriting method chains with pipe)

import { Array, pipe } from "effect"
const numbers = [1, 2, 3, 4]
const double = (n: number) => n * 2
const greaterThanFour = (n: number) => n > 4
pipe(
numbers,
Array.map(double),
Array.filter(greaterThanFour)
) // => [6, 8]

SK

Added in v2.0.0 Source

Returns the second argument and discards the first. The SK combinator is a fundamental combinator in the lambda calculus and the SKI combinator calculus.

When to use

Use to discard the first argument and return the second argument.

Signature

declare function SK<A, B>(_: A, b: B): B

Example

(Discarding the first argument)

import { Function } from "effect"
Function.SK(0, "hello") // => "hello"

tupled

Added in v2.0.0 Source

Creates a tupled version of this function: instead of n arguments, it accepts a single tuple argument.

When to use

Use to adapt a multi-argument function so it accepts one tuple argument.

See

  • untupled for adapting a tuple-argument function back to multiple arguments

Signature

declare function tupled<A extends readonly Array<unknown>, B>(f: (...a: A) => B): (a: A) => B

Example

(Converting arguments to a tuple)

import { Function } from "effect"
const sumTupled = Function.tupled((x: number, y: number): number => x + y)
sumTupled([1, 2]) // => 3

untupled

Added in v2.0.0 Source

Converts a tupled function back to an uncurried function.

When to use

Use to adapt a tuple-argument function so it accepts multiple arguments.

See

  • tupled for adapting a multi-argument function to one tuple argument

Signature

declare function untupled<A extends readonly Array<unknown>, B>(f: (a: A) => B): (...a: A) => B

Example

(Converting a tuple to arguments)

import { Function } from "effect"
const getFirst = Function.untupled(<A, B>(tuple: [A, B]): A => tuple[0])
getFirst(1, 2) // => 1

Constants

constFalse

Added in v2.0.0 Source

Returns false when called.

When to use

Use when you need a thunk that returns false on every invocation.

Signature

declare const constFalse: LazyArg<boolean>

Example

(Returning false from a thunk)

import { Function } from "effect"
Function.constFalse() // => false

constNull

Added in v2.0.0 Source

Returns null when called.

When to use

Use when you need a thunk that returns null on every invocation.

Signature

declare const constNull: LazyArg<null>

Example

(Returning null from a thunk)

import { Function } from "effect"
Function.constNull() // => null

constTrue

Added in v2.0.0 Source

Returns true when called.

When to use

Use when you need a thunk that returns true on every invocation.

Signature

declare const constTrue: LazyArg<boolean>

Example

(Returning true from a thunk)

import { Function } from "effect"
Function.constTrue() // => true

Returns undefined when called.

When to use

Use when you need a thunk that returns undefined on every invocation.

Signature

declare const constUndefined: LazyArg<undefined>

Example

(Returning undefined from a thunk)

import { Function } from "effect"
Function.constUndefined() // => undefined

constVoid

Added in v2.0.0 Source

Returns no meaningful value when called.

When to use

Use when you need a thunk that is called only for its effect and has no meaningful return value.

Signature

declare const constVoid: LazyArg<void>

Example

(Returning void from a thunk)

import { Function } from "effect"
Function.constVoid() // => undefined

Constructors

constant

Added in v2.0.0 Source

Creates a zero-argument function that always returns the provided value.

When to use

Use when you need a thunk or callback that returns the same value on every invocation.

Signature

declare function constant<A>(value: A): LazyArg<A>

Example

(Creating a constant thunk)

import { Function } from "effect"
const constNull = Function.constant(null)
constNull() // => null
constNull() // => null

Models

FunctionN type

Added in v2.0.0 Source

Represents a function with multiple arguments.

When to use

Use to describe a function whose argument list is represented as a tuple type.

Signature

type FunctionN<A extends ReadonlyArray<unknown>, B> = (...args: A) => B

Example

(Typing a variadic function)

import type { Function } from "effect"
const sum: Function.FunctionN<[number, number], number> = (a, b) => a + b
sum(2, 3) // => 5

LazyArg type

Added in v2.0.0 Source

A zero-argument function that produces a value when invoked.

When to use

Use to type a lazy value provider that should not run until called.

Signature

type LazyArg<A> = () => A

Example

(Creating a lazy argument)

import { Function } from "effect"
const constNull: Function.LazyArg<null> = Function.constant(null)
constNull() // => null

Utility Types

absurd

Added in v2.0.0 Source

Marks an impossible branch by accepting a never value and returning any type.

When to use

Use when you need a return value in a branch that exhaustive checks prove cannot be reached.

Gotchas

Calling absurd throws, because a value of type never should be impossible at runtime.

Signature

declare function absurd<A>(_: never): A

Example

(Handling impossible values)

import { absurd } from "effect"
const handleNever = (value: never) => {
return absurd(value) // This will throw an error if called
}

cast

Added in v4.0.0 Source

Returns the input value with a different static type.

When to use

Use when you need an explicit type-level cast and accept that the value is returned unchanged at runtime.

Gotchas

This is a type-level cast only; it performs no runtime validation or conversion.

See

  • satisfies for checking assignability without changing the resulting type

Signature

declare const cast: <A, B>(a: A) => B

FunctionTypeLambda interface

Added in v2.0.0 Source

Type lambda for function types, used for higher-kinded type operations.

When to use

Use when defining higher-kinded abstractions that must accept function types as one of their type-lambda inputs.

Signature

interface FunctionTypeLambda extends TypeLambda {
readonly type: (a: unknown) => unknown;
}

Example

(Creating a function type with a type lambda)

import type { Function, HKT } from "effect"
// Create a function type using the type lambda
type StringToNumber = HKT.Kind<Function.FunctionTypeLambda, string, never, never, number>
// Equivalent to: (a: string) => number

hole

Added in v2.0.0 Source

Creates a compile-time placeholder for a value of any type.

When to use

Use as a temporary typed placeholder while developing incomplete code.

Gotchas

hole is intended for temporary development use. If the placeholder is evaluated at runtime, it throws.

Signature

declare const hole: <T>() => T

Example

(Creating a development placeholder)

import { hole } from "effect"
// Intentionally not called: `hole` throws if the placeholder is evaluated.
const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
id,
name: hole<string>()
})

satisfies

Added in v2.0.0 Source

Ensures that the type of an expression matches some type, without changing the resulting type of that expression.

When to use

Use to check assignability while preserving the expression's precise inferred type.

See

  • cast for changing only the static TypeScript type

Signature

declare function satisfies<A>(): <B>(b: B) => B

Example

(Checking an expression against a type)

import { Function } from "effect"
const test1 = Function.satisfies<number>()(5 as const) // => 5
// ^? const test: 5
// @ts-expect-error
const test2 = Function.satisfies<string>()(5)
// ^? Argument of type 'number' is not assignable to parameter of type 'string'