Tuple
Works with fixed-length arrays, also called tuples.
The runtime helpers in this module create new tuples instead of mutating their inputs, and the types preserve element positions where possible. The helpers cover tuple construction, indexed access, selecting or removing positions, appending values, transforming elements, renaming indices, mapping typed positions, and deriving comparison or combination helpers for tuple shapes.
Combining
appendElement
Appends a single element to the end of a tuple.
When to use
Use when you need the appended value to remain part of the tuple's type-level shape and preserve literal element positions.
Details
The result type is [...T, E], preserving all existing element types.
See
- appendElements – append multiple elements (another tuple)
Signature
declare const appendElement: { <E>(element: E): <T extends readonly Array<unknown>>(self: T) => [...Array<T>, E]; <T extends readonly Array<unknown>, E>(self: T, element: E): [...Array<T>, E];}Example
(Appending an element)
import { pipe, Tuple } from "effect"
pipe(Tuple.make(1, 2), Tuple.appendElement("end")) // => [1, 2, "end"]appendElements
Concatenates two tuples into a single tuple.
When to use
Use to append all elements from one tuple to another tuple.
Details
The result type is [...T1, ...T2], preserving all element types from both
tuples. Neither input tuple is mutated; a fresh tuple is returned.
See
- appendElement – append a single element
Signature
declare const appendElements: { <T2 extends readonly Array<unknown>>(that: T2): <T1 extends readonly Array<unknown>>(self: T1) => [...Array<T1>, ...Array<T2>]; <T1 extends readonly Array<unknown>, T2 extends readonly Array<unknown>>(self: T1, that: T2): [...Array<T1>, ...Array<T2>];}Example
(Concatenating tuples)
import { pipe, Tuple } from "effect"
pipe(Tuple.make(1, 2), Tuple.appendElements(["a", "b"] as const)) // => [1, 2, "a", "b"]makeCombiner
Creates a Combiner for a tuple shape by providing a Combiner for each
position. When two tuples are combined, each element is merged using its
corresponding combiner.
When to use
Use when you need to merge two same-shape tuples by combining each position independently, such as summing counters or concatenating strings.
See
- makeReducer – like
makeCombinerbut with an initial value
Signature
declare function makeCombiner<A extends readonly Array<unknown>>(combiners: { [K in string | number | symbol]: Combiner<A[K]> }): Combiner<A>Example
(Combining tuple elements)
import { Number, String, Tuple } from "effect"
const C = Tuple.makeCombiner<readonly [number, string]>([ Number.ReducerSum, String.ReducerConcat])
C.combine([1, "hello"], [2, " world"]) // => [3, "hello world"]Constructors
Creates a tuple from the provided arguments.
When to use
Use when you need a properly typed tuple without writing [a, b, c] as const
or another manual cast.
Details
The returned value has the exact tuple type, with each element's literal type preserved.
See
- get – access a single element by index
- appendElement – append an element to a tuple
Signature
declare function make<Elements extends readonly Array<unknown>>(...elements: [...Array<Elements>]): [...Array<Elements>]Example
(Creating a tuple)
import { Tuple } from "effect"
Tuple.make(10, 20, "red") // => [10, 20, "red"]Filtering
Creates a new tuple with the elements at the specified indices removed.
When to use
Use to drop elements from a tuple by position.
Details
Elements not at the specified indices are kept in their original order.
See
- pick – the inverse (keep only specified indices)
Signature
declare const omit: { <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>>(indices: I): (self: T) => _BuildTuple<T, Exclude<Exclude<Partial<T>["length"], T["length"]>, I[number]>>; <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>>(self: T, indices: I): _BuildTuple<T, Exclude<Exclude<Partial<T>["length"], T["length"]>, I[number]>>;}Example
(Removing elements by index)
import { Tuple } from "effect"
Tuple.omit(["a", "b", "c", "d"], [1, 3]) // => ["a", "c"]Creates a new tuple containing only the elements at the specified indices.
When to use
Use to select a subset of elements from a tuple by position.
Details
The result order matches the order of the provided indices.
See
Signature
declare const pick: { <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>>(indices: I): (self: T) => PickTuple<T, I>; <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>>(self: T, indices: I): PickTuple<T, I>;}Example
(Selecting elements by index)
import { Tuple } from "effect"
Tuple.pick(["a", "b", "c", "d"], [0, 2, 3]) // => ["a", "c", "d"]Folding
makeReducer
Creates a Reducer for a tuple shape by providing a Reducer for each
position. The initial value is derived from each position's
Reducer.initialValue. When reducing a collection of tuples, each element
is combined independently.
When to use
Use when you need to fold same-shape tuples by accumulating each position independently into one summary tuple.
See
- makeCombiner – like
makeReducerbut without an initial value
Signature
declare function makeReducer<A extends readonly Array<unknown>>(reducers: { [K in string | number | symbol]: Reducer<A[K]> }): Reducer<A>Example
(Reducing a collection of tuples)
import { Number, String, Tuple } from "effect"
const R = Tuple.makeReducer<readonly [number, string]>([ Number.ReducerSum, String.ReducerConcat])
R.combineAll([ [1, "a"], [2, "b"], [3, "c"]]) // => [6, "abc"]Getters
Retrieves the element at the specified index from a tuple.
When to use
Use when a single tuple element should be extracted in a pipeline.
Details
The index is constrained to valid tuple positions at the type level.
See
Signature
declare const get: { <T extends readonly Array<unknown>, I extends never>(index: I): (self: T) => T[I]; <T extends readonly Array<unknown>, I extends never>(self: T, index: I): T[I];}Example
(Extracting an element by index)
import { pipe, Tuple } from "effect"
pipe(Tuple.make(1, true, "hello"), Tuple.get(2)) // => "hello"Guards
Checks whether a readonly array has exactly n elements.
When to use
Use when you need a Predicate guard for exact tuple length that narrows
ReadonlyArray<T> to TupleOf<N, T>.
Details
This only checks length, not element types, and returns a refinement on the array type.
See
Signature
declare const isTupleOf: { <N extends number>(n: N): <T>(self: readonly Array<T>) => self is TupleOf<N, T>; <T, N extends number>(self: readonly Array<T>, n: N): self is TupleOf<N, T>;}Example
(Checking exact length)
import { Predicate } from "effect"
const isPair = Predicate.isTupleOf(2)
isPair([1, 2]) // => trueisTupleOfAtLeast
Checks whether a readonly array has at least n elements.
When to use
Use when you need a Predicate guard for tuple-like minimum length that
narrows ReadonlyArray<T> to TupleOfAtLeast<N, T>.
Details
This only checks length, not element types, and returns a refinement on the array type.
See
Signature
declare const isTupleOfAtLeast: { <N extends number>(n: N): <T>(self: readonly Array<T>) => self is [...Array<TupleOf<N, T>>, ...Array<T>]; <T, N extends number>(self: readonly Array<T>, n: N): self is [...Array<TupleOf<N, T>>, ...Array<T>];}Example
(Checking minimum length)
import { Predicate } from "effect"
const hasAtLeast2 = Predicate.isTupleOfAtLeast(2)
hasAtLeast2([1, 2, 3]) // => trueInstances
makeEquivalence
Creates an Equivalence for tuples by comparing corresponding elements
using the provided per-position Equivalences. Two tuples are equivalent
when all their corresponding elements are equivalent.
When to use
Use when you need an Equivalence to compare tuples element-by-element.
Details
This is an alias of Equivalence.Tuple.
See
- makeOrder – create an
Orderfor tuples
Signature
declare const makeEquivalence: <Elements extends readonly Array<Equivalence<any>>>(elements: Elements) => Equivalence<{ [I in string | number | symbol]: [Elements[I]] extends [Equivalence<A>] ? A : never }>Example
(Comparing tuples for equivalence)
import { Equivalence, Tuple } from "effect"
const eq = Tuple.makeEquivalence([ Equivalence.strictEqual<string>(), Equivalence.strictEqual<number>()])
eq(["Alice", 30], ["Alice", 30]) // => trueeq(["Alice", 30], ["Bob", 30]) // => falseMapping
Transforms elements of a tuple by providing an array of transform functions. Each function applies to the element at the same position. Positions beyond the array's length are copied unchanged.
When to use
Use when you want to update the first N elements while keeping the rest.
Details
Each transform function receives the current value and can return a different type.
See
- map – apply the same transformation to all elements
- renameIndices – swap element positions
Signature
declare const evolve: { <T extends readonly Array<unknown>, E extends Evolver<T>>(evolver: E): (self: T) => Evolved<T, E>; <T extends readonly Array<unknown>, E extends Evolver<T>>(self: T, evolver: E): Evolved<T, E>;}Example
(Transforming selected elements)
import { pipe, Tuple } from "effect"
pipe( Tuple.make("hello", 42, true), Tuple.evolve([ (s) => s.toUpperCase(), (n) => n * 2 ])) // => ["HELLO", 84, true]Applies a Struct.Lambda transformation to every element in a tuple.
When to use
Use when you want to apply the same transformation to every tuple element.
Details
The lambda lets the compiler track the output type for each element.
Gotchas
The lambda must be created with Struct.lambda; a plain function will not
type-check.
See
Signature
declare const map: { <L extends Lambda>(lambda: L): <T extends readonly Array<unknown>>(self: T) => { [K in string | number | symbol]: Apply<L, T[K]> }; <T extends readonly Array<unknown>, L extends Lambda>(self: T, lambda: L): { [K in string | number | symbol]: Apply<L, T[K]> };}Example
(Wrapping every element in an array)
import { pipe, Struct, Tuple } from "effect"
interface AsArray extends Struct.Lambda { <A>(self: A): Array<A> readonly "~lambda.out": Array<this["~lambda.in"]>}
const asArray = Struct.lambda<AsArray>((a) => [a])pipe(Tuple.make(1, "hello", true), Tuple.map(asArray)) // => [[1], ["hello"], [true]]Applies a Struct.Lambda transformation to all elements except those at the
specified indices; the excluded elements are copied unchanged.
When to use
Use when most elements should be transformed but a few should be preserved.
See
Signature
declare const mapOmit: { <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>, L extends Lambda>(indices: I, lambda: L): (self: T) => { [K in string | number | symbol]: K extends `${I[number]}` ? T[K] : Apply<L, T[K]> }; <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>, L extends Lambda>(self: T, indices: I, lambda: L): { [K in string | number | symbol]: K extends `${I[number]}` ? T[K] : Apply<L, T[K]> };}Example
(Wrapping all elements except one in arrays)
import { pipe, Struct, Tuple } from "effect"
interface AsArray extends Struct.Lambda { <A>(self: A): Array<A> readonly "~lambda.out": Array<this["~lambda.in"]>}
const asArray = Struct.lambda<AsArray>((a) => [a])pipe( Tuple.make(1, "hello", true), Tuple.mapOmit([1], asArray)) // => [[1], "hello", [true]]Applies a Struct.Lambda transformation only to the elements at the
specified indices; all other elements are copied unchanged.
When to use
Use when you want to apply the same transformation to a subset of positions.
See
Signature
declare const mapPick: { <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>, L extends Lambda>(indices: I, lambda: L): (self: T) => { [K in string | number | symbol]: K extends `${I[number]}` ? Apply<L, T[K]> : T[K] }; <T extends readonly Array<unknown>, I extends readonly Array<Exclude<Partial<T>["length"], T["length"]>>, L extends Lambda>(self: T, indices: I, lambda: L): { [K in string | number | symbol]: K extends `${I[number]}` ? Apply<L, T[K]> : T[K] };}Example
(Wrapping only selected elements in arrays)
import { pipe, Struct, Tuple } from "effect"
interface AsArray extends Struct.Lambda { <A>(self: A): Array<A> readonly "~lambda.out": Array<this["~lambda.in"]>}
const asArray = Struct.lambda<AsArray>((a) => [a])pipe( Tuple.make(1, "hello", true), Tuple.mapPick([0, 2], asArray)) // => [[1], "hello", [true]]Ordering
Creates an Order for tuples by comparing corresponding elements using the
provided per-position Orders. Elements are compared left-to-right; the
first non-zero comparison determines the result.
When to use
Use when you need to sort fixed-position arrays lexicographically, with each position using its own ordering rule.
Details
This is an alias of Order.Tuple.
See
- makeEquivalence – create an
Equivalencefor tuples
Signature
declare const makeOrder: <Elements extends readonly Array<Order<any>>>(elements: Elements) => Order<{ [I in string | number | symbol]: [Elements[I]] extends [Order<A>] ? A : never }>Example
(Ordering tuples)
import { Number, String, Tuple } from "effect"
const ord = Tuple.makeOrder([String.Order, Number.Order])
ord(["Alice", 30], ["Bob", 25]) // => -1ord(["Alice", 30], ["Alice", 30]) // => 0Transforming
renameIndices
Renames tuple indices by providing an array of stringified source
indices. Each position in the array specifies which index to read from
(e.g., ["2", "1", "0"] reverses a 3-element tuple).
When to use
Use to reorder tuple elements while preserving index-specific types.
Details
The mapping returns a tuple in the requested index order.
Gotchas
The mapping uses stringified source indices, not arbitrary names.
See
- evolve – transform element values instead of positions
Signature
declare const renameIndices: { <T extends readonly Array<unknown>, M extends { [I in string | number | symbol]: `${keyof T & string}` }>(mapping: M): (self: T) => { [I in string | number | symbol]: I extends keyof M ? M[I] extends keyof T ? T[any[any]] : T[I] : T[I] }; <T extends readonly Array<unknown>, M extends { [I in string | number | symbol]: `${keyof T & string}` }>(self: T, mapping: M): { [I in string | number | symbol]: I extends keyof M ? M[I] extends keyof T ? T[any[any]] : T[I] : T[I] };}Example
(Swapping elements)
import { pipe, Tuple } from "effect"
pipe( Tuple.make("a", "b", "c"), Tuple.renameIndices(["2", "1", "0"])) // => ["c", "b", "a"]