Skip to content

Array

The Array module is a functional toolkit for working with JavaScript arrays. It operates on plain ReadonlyArray<A> values — the built-in array type — and adds constructors, transformations, searches, folds, grouping, sorting, and set-like operations around them.

Three properties hold across the whole module:

  • Nothing mutates. Operations that transform, reorder, or update a collection allocate a new array; your input is left untouched.
  • Functions are dual. Every combinator can be called data-first (Array.map(xs, f)) or data-last for pipelines (pipe(xs, Array.map(f))).
  • Non-emptiness is tracked in the type. NonEmptyReadonlyArray<A> (and its mutable twin NonEmptyArray<A>) encode “at least one element” at the type level, so APIs like headNonEmpty can return A directly instead of Option<A>.
import { Array } from "effect"
// import the namespace — `Array` shadows the TS global on purpose,
// and Array.Array still exposes the native constructor if you need it.

Most real code is a pipe of small steps. Here is a filter / map / group sequence in data-last style.

import { Array, pipe } from "effect"
const orders = [
{ id: 1, region: "us", total: 120 },
{ id: 2, region: "eu", total: 80 },
{ id: 3, region: "us", total: 50 },
{ id: 4, region: "eu", total: 200 }
]
const byRegion = pipe(
orders,
Array.filter((o) => o.total >= 60), // drop small orders
Array.map((o) => ({ ...o, total: o.total * 1.1 })), // add 10% fee
Array.groupBy((o) => o.region) // bucket by region
)
console.log(byRegion)
// {
// us: [{ id: 1, region: "us", total: 132 }],
// eu: [{ id: 2, region: "eu", total: 88 }, { id: 4, region: "eu", total: 220 }]
// }

A NonEmptyReadonlyArray<A> is just readonly [A, ...Array<A>]. Because the first slot is guaranteed, total functions can skip Option:

import { Array } from "effect"
declare const xs: Array.NonEmptyReadonlyArray<number>
Array.headNonEmpty(xs) // : number (not Option<number>)
Array.head([1, 2, 3]) // : Option<number> on a plain array

isArrayNonEmpty / isReadonlyArrayNonEmpty are refinements: passing the guard narrows the value so the NonEmpty APIs become available.

import { Array } from "effect"
const parse = (input: ReadonlyArray<number>) => {
if (Array.isReadonlyArrayNonEmpty(input)) {
// `input` is now NonEmptyReadonlyArray<number>
return Array.headNonEmpty(input) // number, no Option
}
return 0
}

Operations that can prove the result is non-empty preserve the type: map, sort, reverse, prepend, append, intersperse, rotate, copy, dedupe, and the *NonEmpty variants all return NonEmptyArray when given non-empty input.


Creates a NonEmptyArray from one or more literal elements; the element type is the union of all arguments.

import { Array } from "effect"
Array.make(1, 2, 3) // => [1, 2, 3] (NonEmptyArray<number>)

Creates an Array of the given length with uninitialized slots, typed as A | undefined. Fill it imperatively.

import { Array } from "effect"
Array.allocate<number>(3).length // => 3

Builds a NonEmptyArray of length n (normalized to >= 1) where element i is f(i).

import { Array } from "effect"
Array.makeBy(5, (n) => n * 2) // => [0, 2, 4, 6, 8]

Creates a NonEmptyArray of consecutive integers, inclusive on both ends. If start > end, returns [start].

import { Array } from "effect"
Array.range(1, 3) // => [1, 2, 3]
Array.range(5, 2) // => [5]

Creates a NonEmptyArray with a value repeated n times (n normalized to >= 1).

import { Array } from "effect"
Array.replicate("a", 3) // => ["a", "a", "a"]

Converts any Iterable to an Array. If the input is already an array it is returned by reference (no copy) — use copy for a fresh array.

import { Array } from "effect"
Array.fromIterable(new Set([1, 2, 3])) // => [1, 2, 3]

Normalizes a value that may be a single element or an array into an array. Handy for APIs that accept A | Array<A>.

import { Array } from "effect"
Array.ensure("a") // => ["a"]
Array.ensure(["a", "b"]) // => ["a", "b"]

Converts a record into an array of [key, value] tuples, following Object.entries order.

import { Array } from "effect"
Array.fromRecord({ a: 1, b: 2 }) // => [["a", 1], ["b", 2]]

Converts an Option to an array: Some(a) becomes [a], None becomes [].

import { Array, Option } from "effect"
Array.fromOption(Option.some(1)) // => [1]
Array.fromOption(Option.none()) // => []

Creates a typed empty array.

import { Array } from "effect"
Array.empty<number>() // => []

Wraps a single value in a NonEmptyArray.

import { Array } from "effect"
Array.of(1) // => [1]

Builds an array by repeatedly applying a function to a seed. Return Option.some([element, nextSeed]) to continue, Option.none() to stop.

import { Array, Option } from "effect"
Array.unfold(1, (n) => (n <= 5 ? Option.some([n, n + 1]) : Option.none()))
// => [1, 2, 3, 4, 5]

Adds a single element to the front, always returning a NonEmptyArray.

import { Array } from "effect"
Array.prepend([2, 3, 4], 1) // => [1, 2, 3, 4]

Prepends all elements of a prefix iterable. Non-empty if either input is non-empty.

import { Array } from "effect"
Array.prependAll([2, 3], [0, 1]) // => [0, 1, 2, 3]

Adds a single element to the end, always returning a NonEmptyArray.

import { Array } from "effect"
Array.append([1, 2, 3], 4) // => [1, 2, 3, 4]

Concatenates two iterables. Non-empty if either input is non-empty.

import { Array } from "effect"
Array.appendAll([1, 2], [3, 4]) // => [1, 2, 3, 4]

Type guard for native arrays, narrowing to Array<unknown>. Delegates to globalThis.Array.isArray.

import { Array } from "effect"
Array.isArray([1, 2, 3]) // => true
Array.isArray(null) // => false

Checks whether a mutable Array is empty, narrowing to [].

import { Array } from "effect"
Array.isArrayEmpty([]) // => true
Array.isArrayEmpty([1]) // => false

Readonly counterpart of isArrayEmpty, narrowing to readonly [].

import { Array } from "effect"
Array.isReadonlyArrayEmpty([] as ReadonlyArray<number>) // => true

Checks whether a mutable Array is non-empty, narrowing to NonEmptyArray.

import { Array } from "effect"
Array.isArrayNonEmpty([1, 2, 3]) // => true
Array.isArrayNonEmpty([]) // => false

Readonly counterpart of isArrayNonEmpty, narrowing to NonEmptyReadonlyArray.

import { Array } from "effect"
Array.isReadonlyArrayNonEmpty([1] as ReadonlyArray<number>) // => true

The number of elements, as a composable function.

import { Array } from "effect"
Array.length([1, 2, 3]) // => 3

Reads an element at an index safely, returning Option. The index is floored; out-of-bounds returns None.

import { Array } from "effect"
Array.get([1, 2, 3], 1) // => Option.some(2)
Array.get([1, 2, 3], 10) // => Option.none()

Reads an element at an index, throwing "Index out of bounds: <i>" if invalid. Prefer get for safe access.

import { Array } from "effect"
Array.getUnsafe([1, 2, 3], 1) // => 2
// Array.getUnsafe([1, 2, 3], 10) // throws Error

The first element as an Option, or None for an empty array.

import { Array } from "effect"
Array.head([1, 2, 3]) // => Option.some(1)
Array.head([]) // => Option.none()

The first element of a NonEmptyReadonlyArray, returned directly without Option.

import { Array } from "effect"
Array.headNonEmpty([1, 2, 3]) // => 1

The last element as an Option, or None for an empty array.

import { Array } from "effect"
Array.last([1, 2, 3]) // => Option.some(3)
Array.last([]) // => Option.none()

The last element of a NonEmptyReadonlyArray, returned directly.

import { Array } from "effect"
Array.lastNonEmpty([1, 2, 3]) // => 3

All elements except the first, as an Option (allocates via slice(1)).

import { Array } from "effect"
Array.tail([1, 2, 3]) // => Option.some([2, 3])
Array.tail([]) // => Option.none()

All elements after the first of a NonEmptyReadonlyArray.

import { Array } from "effect"
Array.tailNonEmpty([1, 2, 3]) // => [2, 3]

All elements except the last, as an Option (allocates via slice(0, -1)).

import { Array } from "effect"
Array.init([1, 2, 3]) // => Option.some([1, 2])
Array.init([]) // => Option.none()

All elements before the last of a NonEmptyReadonlyArray.

import { Array } from "effect"
Array.initNonEmpty([1, 2, 3]) // => [1, 2]

Splits a NonEmptyReadonlyArray into [head, tail].

import { Array } from "effect"
Array.unprepend([1, 2, 3, 4]) // => [1, [2, 3, 4]]

Splits a NonEmptyReadonlyArray into [init, last].

import { Array } from "effect"
Array.unappend([1, 2, 3, 4]) // => [[1, 2, 3], 4]

Keeps the first n elements (n clamped to [0, length]).

import { Array } from "effect"
Array.take([1, 2, 3, 4, 5], 3) // => [1, 2, 3]

Keeps the last n elements (n clamped to [0, length]).

import { Array } from "effect"
Array.takeRight([1, 2, 3, 4, 5], 3) // => [3, 4, 5]

Keeps the leading prefix while the predicate holds, stopping at the first failure. Supports refinements. The predicate receives (element, index).

import { Array } from "effect"
Array.takeWhile([1, 3, 2, 4, 1], (x) => x < 4) // => [1, 3, 2]

Keeps the leading prefix while a Result-returning filter succeeds, collecting the transformed success values. Stops at the first failure.

import { Array, Result } from "effect"
Array.takeWhileFilter([1, 2, 9, 3], (n) =>
n < 5 ? Result.succeed(n * 10) : Result.failVoid
)
// => [10, 20]

Splits into the longest matching prefix and the rest in a single pass — like [takeWhile(p), dropWhile(p)]. Supports refinements on the prefix.

import { Array } from "effect"
Array.span([1, 3, 2, 4, 5], (x) => x % 2 === 1) // => [[1, 3], [2, 4, 5]]

Removes the first n elements (n clamped to [0, length]).

import { Array } from "effect"
Array.drop([1, 2, 3, 4, 5], 2) // => [3, 4, 5]

Removes the last n elements (n clamped to [0, length]).

import { Array } from "effect"
Array.dropRight([1, 2, 3, 4, 5], 2) // => [1, 2, 3]

Removes the leading prefix while the predicate holds, returning the rest.

import { Array } from "effect"
Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4) // => [4, 5]

Removes the leading prefix while a Result-returning filter succeeds, returning the remaining original elements.

import { Array, Result } from "effect"
Array.dropWhileFilter([1, 2, 9, 3], (n) =>
n < 5 ? Result.succeed(n) : Result.failVoid
)
// => [9, 3]

Splits an iterable into a prefix and suffix at the given index (n floored, may be 0).

import { Array } from "effect"
Array.splitAt([1, 2, 3, 4, 5], 3) // => [[1, 2, 3], [4, 5]]

Splits a NonEmptyReadonlyArray so the first part is guaranteed non-empty (n clamped to >= 1).

import { Array } from "effect"
Array.splitAtNonEmpty(["a", "b", "c", "d"], 2) // => [["a", "b"], ["c", "d"]]

Splits an iterable into n roughly equal chunks; the last chunk may be shorter.

import { Array } from "effect"
Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) // => [[1, 2, 3], [4, 5, 6], [7, 8]]

Splits at the first element matching the predicate; the matching element starts the second array.

import { Array } from "effect"
Array.splitWhere([1, 2, 3, 4, 5], (n) => n > 3) // => [[1, 2, 3], [4, 5]]

Splits an iterable into non-overlapping chunks of length n; the last may be shorter. Each chunk is a NonEmptyArray. chunksOf(n)([]) is [].

import { Array } from "effect"
Array.chunksOf([1, 2, 3, 4, 5], 2) // => [[1, 2], [3, 4], [5]]

Creates overlapping sliding windows of size n. Returns [] if n <= 0 or the array is shorter than n.

import { Array } from "effect"
Array.window([1, 2, 3, 4, 5], 3) // => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
Array.window([1, 2], 6) // => []

Creates a shallow copy, preserving NonEmptyArray in the type. Useful when you need a distinct reference (unlike fromIterable, which returns arrays by reference).

import { Array } from "effect"
const original = [1, 2, 3]
const copied = Array.copy(original)
original === copied // => false

Pads or truncates to exactly n elements: fills with fill if shorter, slices if longer. Returns [] when n <= 0.

import { Array } from "effect"
Array.pad([1, 2, 3], 6, 0) // => [1, 2, 3, 0, 0, 0]
Array.pad([1, 2, 3], 2, 0) // => [1, 2]

Repeatedly consumes prefixes via a function returning [value, rest], until the remaining array is empty. The basis for custom splitting/grouping.

import { Array } from "effect"
Array.chop([1, 2, 3, 4], (as): [number, Array<number>] => [as[0] * 2, as.slice(1)])
// => [2, 4, 6, 8]

The index of the first element matching the predicate, as an Option.

import { Array } from "effect"
Array.findFirstIndex([5, 3, 8, 9], (x) => x > 5) // => Option.some(2)

The index of the last element matching the predicate, as an Option.

import { Array } from "effect"
Array.findLastIndex([1, 3, 8, 9], (x) => x < 5) // => Option.some(1)

The first element matching a predicate, refinement, or Option-returning function (find-and-transform), as an Option.

import { Array } from "effect"
Array.findFirst([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some(4)

Like findFirst, but returns Option.some([value, index]) for the first match.

import { Array } from "effect"
Array.findFirstWithIndex([1, 2, 3, 4, 5], (x) => x > 3) // => Option.some([4, 3])

The last element matching a predicate, refinement, or Option-returning function, searching from the end.

import { Array } from "effect"
Array.findLast([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => Option.some(4)

Checks membership using Effect’s default equality (Equal.asEquivalence()).

import { Array } from "effect"
Array.contains(["a", "b", "c"], "c") // => true

Returns a membership-test function using a custom equivalence.

import { Array, pipe } from "effect"
const containsNum = Array.containsWith((a: number, b: number) => a === b)
pipe([1, 2, 3], containsNum(3)) // => true

All of these return new arrays; the input is never mutated.

Inserts an element at an index safely, returning Option<NonEmptyArray>. Valid indices are 0 to length (inserting at length appends).

import { Array } from "effect"
Array.insertAt(["a", "b", "c", "e"], 3, "d") // => Option.some(["a", "b", "c", "d", "e"])

Replaces the element at an index with a fixed value, returning Option. None if out of bounds.

import { Array } from "effect"
Array.replace([1, 2, 3], 1, 4) // => Option.some([1, 4, 3])

Applies a function to the element at an index, returning Option. None if out of bounds.

import { Array } from "effect"
Array.modify([1, 2, 3, 4], 2, (n) => n * 2) // => Option.some([1, 2, 6, 4])
Array.modify([1, 2, 3, 4], 5, (n) => n * 2) // => Option.none()

Removes the element at an index; returns a copy of the original if the index is out of bounds.

import { Array } from "effect"
Array.remove([1, 2, 3, 4], 2) // => [1, 2, 4]
Array.remove([1, 2, 3, 4], 5) // => [1, 2, 3, 4]

Reverses into a new array, preserving NonEmptyArray.

import { Array } from "effect"
Array.reverse([1, 2, 3, 4]) // => [4, 3, 2, 1]

Rotates by n steps: positive rotates right, negative rotates left, wrapping around. n is rounded; preserves NonEmptyArray.

import { Array } from "effect"
Array.rotate(["a", "b", "c", "d"], 2) // => ["c", "d", "a", "b"]

Inserts a separator between every pair of elements, preserving NonEmptyArray. Empty input yields empty output.

import { Array } from "effect"
Array.intersperse([1, 2, 3], 0) // => [1, 0, 2, 0, 3]

Transforms the first element of a NonEmptyReadonlyArray.

import { Array } from "effect"
Array.modifyHeadNonEmpty([1, 2, 3], (n) => n * 10) // => [10, 2, 3]

Replaces the first element of a NonEmptyReadonlyArray with a fixed value.

import { Array } from "effect"
Array.setHeadNonEmpty([1, 2, 3], 10) // => [10, 2, 3]

Transforms the last element of a NonEmptyReadonlyArray.

import { Array } from "effect"
Array.modifyLastNonEmpty([1, 2, 3], (n) => n * 2) // => [1, 2, 6]

Replaces the last element of a NonEmptyReadonlyArray with a fixed value.

import { Array } from "effect"
Array.setLastNonEmpty([1, 2, 3], 4) // => [1, 2, 4]

Sorts by an Order, preserving NonEmptyArray.

import { Array, Order } from "effect"
Array.sort([3, 1, 4, 1, 5], Order.Number) // => [1, 1, 3, 4, 5]

Sorts by a derived key using a mapping function plus an Order for that key. Equivalent to sort(Order.mapInput(order, f)).

import { Array, Order } from "effect"
Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.Number) // => ["b", "cc", "aaa"]

Sorts by multiple Orders in sequence: later orders break ties from earlier ones. Data-last only; preserves NonEmptyArray.

import { Array, Order, pipe } from "effect"
type User = { name: string; age: number }
const users: Array<User> = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 30 }
]
pipe(
users,
Array.sortBy(
Order.mapInput(Order.Number, (u: User) => u.age),
Order.mapInput(Order.String, (u: User) => u.name)
)
)
// => [{ name: "Bob", age: 25 }, { name: "Alice", age: 30 }, { name: "Charlie", age: 30 }]

The minimum element of a NonEmptyReadonlyArray by an Order.

import { Array, Order } from "effect"
Array.min([3, 1, 2], Order.Number) // => 1

The maximum element of a NonEmptyReadonlyArray by an Order.

import { Array, Order } from "effect"
Array.max([3, 1, 2], Order.Number) // => 3

Creates an Order for arrays from an element Order. Arrays are compared element-wise; ties go to the shorter array.

import { Array, Order } from "effect"
const arrayOrder = Array.makeOrder(Order.Number)
arrayOrder([1, 2], [1, 3]) // => -1

Creates an Equivalence for arrays from an element Equivalence. Equal when lengths match and all elements are pairwise equivalent.

import { Array } from "effect"
const eq = Array.makeEquivalence<number>((a, b) => a === b)
eq([1, 2, 3], [1, 2, 3]) // => true

Pairs elements by position; extra elements from the longer iterable are discarded. NonEmptyArray when both inputs are non-empty.

import { Array } from "effect"
Array.zip([1, 2, 3], ["a", "b"]) // => [[1, "a"], [2, "b"]]

Combines elements pairwise using a function; extra elements are discarded.

import { Array } from "effect"
Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) // => [5, 7, 9]

Splits an array of pairs into two arrays — the inverse of zip.

import { Array } from "effect"
Array.unzip([[1, "a"], [2, "b"], [3, "c"]]) // => [[1, 2, 3], ["a", "b", "c"]]

Every [a, b] pair from two arrays as tuples. Result length is self.length * that.length.

import { Array } from "effect"
Array.cartesian([1, 2], ["a", "b"]) // => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]

Like cartesian, but applies a combiner to each pair.

import { Array } from "effect"
Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`)
// => ["1-a", "1-b", "2-a", "2-b"]

Transforms each element, preserving NonEmptyArray. The function receives (element, index).

import { Array } from "effect"
Array.map([1, 2, 3], (x) => x * 2) // => [2, 4, 6]

Maps each element to an array and flattens the results. NonEmptyArray when both input and every mapped array are non-empty.

import { Array } from "effect"
Array.flatMap([1, 2, 3], (x) => [x, x * 2]) // => [1, 2, 2, 4, 3, 6]

Flattens one level of nested arrays.

import { Array } from "effect"
Array.flatten([[1, 2], [], [3, 4], [5, 6]]) // => [1, 2, 3, 4, 5, 6]

Runs a side-effect for each element; returns nothing. The callback receives (element, index).

import { Array } from "effect"
Array.forEach([1, 2, 3], (n) => console.log(n)) // logs 1, 2, 3

Maps with a Result-returning filter, keeping only the success values. Failures are discarded.

import { Array, Result } from "effect"
Array.filterMap([1, 2, 3, 4], (n) =>
n % 2 === 0 ? Result.succeed(n * 10) : Result.failVoid
)
// => [20, 40]

Keeps only elements satisfying a predicate or refinement. Always returns a plain Array.

import { Array } from "effect"
Array.filter([1, 2, 3, 4], (x) => x % 2 === 0) // => [2, 4]

Evaluates each element with a Result-returning filter and keeps both sides, as [excluded, satisfying].

import { Array, Result } from "effect"
Array.partition([1, -2, 3], (n, i) =>
n > 0 ? Result.succeed(n + i) : Result.fail(`negative:${n}`)
)
// => [["negative:-2"], [1, 5]]

Splits an array of existing Results into [failures, successes]. Equivalent to partition(identity).

import { Array, Result } from "effect"
Array.separate([Result.succeed(1), Result.fail("error"), Result.succeed(2)])
// => [["error"], [1, 2]]

Folds left-to-right into a single value. The function receives (accumulator, element, index).

import { Array } from "effect"
Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) // => 6

Folds right-to-left into a single value.

import { Array } from "effect"
Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) // => 6

Maps while threading an accumulator through each step, returning [finalState, mappedArray]. The callback returns [nextState, mappedValue].

import { Array } from "effect"
Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) // => [6, [1, 3, 6]]

Applies a function to each suffix of the array; at index i the function receives self.slice(i).

import { Array } from "effect"
Array.extend([1, 2, 3], (as) => as.length) // => [3, 2, 1]

Folds left-to-right keeping every intermediate accumulator. Output length is input.length + 1, always a NonEmptyArray (starts with the initial value).

import { Array } from "effect"
Array.scan([1, 2, 3, 4], 0, (acc, n) => acc + n) // => [0, 1, 3, 6, 10]

Folds right-to-left keeping every intermediate accumulator. Output ends with the initial value.

import { Array } from "effect"
Array.scanRight([1, 2, 3, 4], 0, (acc, n) => acc + n) // => [10, 9, 7, 4, 0]

Checks whether all elements satisfy the predicate; supports refinements for narrowing.

import { Array } from "effect"
Array.every([2, 4, 6], (x) => x % 2 === 0) // => true
Array.every([2, 3, 6], (x) => x % 2 === 0) // => false

Checks whether at least one element satisfies the predicate, narrowing to NonEmptyReadonlyArray on success.

import { Array } from "effect"
Array.some([1, 3, 4], (x) => x % 2 === 0) // => true
Array.some([1, 3, 5], (x) => x % 2 === 0) // => false

Counts how many elements satisfy a predicate. Returns 0 for an empty iterable.

import { Array } from "effect"
Array.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0) // => 2

Joins string elements with a separator.

import { Array } from "effect"
Array.join(["a", "b", "c"], "-") // => "a-b-c"

Groups consecutive equal elements using Effect’s default equality. Only adjacent equal values are grouped. Requires a NonEmptyReadonlyArray.

import { Array } from "effect"
Array.group([1, 1, 2, 2, 2, 3, 1]) // => [[1, 1], [2, 2, 2], [3], [1]]

Like group, but uses a custom equivalence.

import { Array } from "effect"
Array.groupWith(["a", "a", "b", "b", "c"], (x, y) => x === y)
// => [["a", "a"], ["b", "b"], ["c"]]

Groups all elements into a record by a key-returning function (key must be string or symbol). Elements need not be adjacent.

import { Array } from "effect"
const people = [
{ name: "Alice", team: "A" },
{ name: "Bob", team: "B" },
{ name: "Charlie", team: "A" }
]
Array.groupBy(people, (p) => p.team)
// => {
// A: [{ name: "Alice", team: "A" }, { name: "Charlie", team: "A" }],
// B: [{ name: "Bob", team: "B" }]
// }

Removes all duplicates using default equality, keeping the first occurrence. Preserves NonEmptyArray.

import { Array } from "effect"
Array.dedupe([1, 2, 1, 3, 2, 4]) // => [1, 2, 3, 4]

Like dedupe, but uses a custom equivalence.

import { Array } from "effect"
Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) // => [1, 2, 3]

Removes only consecutive duplicates using default equality; non-adjacent repeats are kept.

import { Array } from "effect"
Array.dedupeAdjacent([1, 1, 2, 2, 3, 1]) // => [1, 2, 3, 1]

Like dedupeAdjacent, but uses a custom equivalence.

import { Array } from "effect"
Array.dedupeAdjacentWith([1, 1, 2, 2, 3], (a, b) => a === b) // => [1, 2, 3]

These use Effect’s Equal protocol by default; the *With variants take a custom equivalence.

Elements present in either array, deduplicated using default equality.

import { Array } from "effect"
Array.union([1, 2], [2, 3]) // => [1, 2, 3]

Like union, but uses a custom equivalence.

import { Array } from "effect"
Array.unionWith([1, 2], [2, 3], (a, b) => a === b) // => [1, 2, 3]

Elements present in both arrays (order from the first), using default equality.

import { Array } from "effect"
Array.intersection([1, 2, 3], [3, 4, 1]) // => [1, 3]

Like intersection, but uses a custom equivalence — useful for matching objects by a field.

import { Array, pipe } from "effect"
const a = [{ id: 1 }, { id: 2 }, { id: 3 }]
const b = [{ id: 3 }, { id: 4 }, { id: 1 }]
const eq = (x: { id: number }, y: { id: number }) => x.id === y.id
pipe(a, Array.intersectionWith(eq)(b)) // => [{ id: 1 }, { id: 3 }]

Elements in the first array that are not in the second, using default equality.

import { Array } from "effect"
Array.difference([1, 2, 3], [2, 3, 4]) // => [1]

Like difference, but uses a custom equivalence.

import { Array } from "effect"
Array.differenceWith<number>((a, b) => a === b)([1, 2, 3], [2, 3, 4]) // => [1]

Extracts all Some values from an iterable of Options, discarding Nones.

import { Array, Option } from "effect"
Array.getSomes([Option.some(1), Option.none(), Option.some(2)]) // => [1, 2]

Extracts all failure values from an iterable of Results, discarding successes.

import { Array, Result } from "effect"
Array.getFailures([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => ["err"]

Extracts all success values from an iterable of Results, discarding failures.

import { Array, Result } from "effect"
Array.getSuccesses([Result.succeed(1), Result.fail("err"), Result.succeed(2)]) // => [1, 2]

Lifts a predicate (or refinement) into an array-returning function: [value] if it holds, [] otherwise.

import { Array } from "effect"
const toEven = Array.liftPredicate((n: number) => n % 2 === 0)
toEven(2) // => [2]
toEven(1) // => []

Lifts an Option-returning function into one that returns an array: Some(a) becomes [a], None becomes [].

import { Array, Option } from "effect"
const parse = Array.liftOption((s: string) => {
const n = Number(s)
return isNaN(n) ? Option.none() : Option.some(n)
})
parse("123") // => [123]
parse("abc") // => []

Lifts a Result-returning function: failures produce [], successes produce [value].

import { Array, Result } from "effect"
const parse = (s: string): Result.Result<number, Error> =>
isNaN(Number(s)) ? Result.fail(new Error("NaN")) : Result.succeed(Number(s))
const lifted = Array.liftResult(parse)
lifted("42") // => [42]
lifted("x") // => []

Converts a nullable value to an array: null/undefined becomes [], anything else becomes [value].

import { Array } from "effect"
Array.fromNullishOr(1) // => [1]
Array.fromNullishOr(null) // => []

Lifts a nullable-returning function: null/undefined produces [], anything else produces [value].

import { Array } from "effect"
const parse = Array.liftNullishOr((s: string) => {
const n = Number(s)
return isNaN(n) ? null : n
})
parse("123") // => [123]
parse("abc") // => []

Maps each element with a nullable-returning function, dropping null/undefined results.

import { Array } from "effect"
Array.flatMapNullishOr([1, 2, 3], (n) => (n % 2 === 0 ? null : n)) // => [1, 3]

Branches on emptiness; onNonEmpty receives the full NonEmptyReadonlyArray.

import { Array } from "effect"
const describe = Array.match({
onEmpty: () => "empty",
onNonEmpty: (xs) => `${xs.length} items`
})
describe([]) // => "empty"
describe([1, 2, 3]) // => "3 items"

Branches on emptiness, destructuring the non-empty case into (head, tail).

import { Array } from "effect"
const m = Array.matchLeft({
onEmpty: () => "empty",
onNonEmpty: (head, tail) => `head: ${head}, rest: ${tail.length}`
})
m([1, 2, 3]) // => "head: 1, rest: 2"

Branches on emptiness, destructuring the non-empty case into (init, last).

import { Array } from "effect"
const m = Array.matchRight({
onEmpty: () => "empty",
onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}`
})
m([1, 2, 3]) // => "init: 2, last: 3"

The do-notation builds an array comprehension: each bind produces the cartesian product with all previous bindings (like nested loops), and filter/map add conditions and transformations.

The starting point — a single-element array of an empty scope.

import { Array, pipe } from "effect"
pipe(
Array.Do,
Array.bind("x", () => [1, 3, 5]),
Array.bind("y", () => [2, 4, 6]),
Array.filter(({ x, y }) => x < y),
Array.map(({ x, y }) => [x, y] as const)
)
// => [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]]

Adds a named array variable to the scope, pairing each existing scope with every value the callback returns.

import { Array, pipe } from "effect"
pipe(
Array.Do,
Array.bind("x", () => [1, 2]),
Array.bind("y", () => ["a", "b"])
)
// => [{ x: 1, y: "a" }, { x: 1, y: "b" }, { x: 2, y: "a" }, { x: 2, y: "b" }]

Adds a computed plain value to the scope (no new array dimension, so no cartesian product).

import { Array, pipe } from "effect"
pipe(
Array.Do,
Array.bind("x", () => [1, 2, 3]),
Array.let("doubled", ({ x }) => x * 2)
)
// => [{ x: 1, doubled: 2 }, { x: 2, doubled: 4 }, { x: 3, doubled: 6 }]

Wraps each element of an existing array in an object with the given key, starting a scope. Equivalent to Array.map(self, (a) => ({ [tag]: a })).

import { Array, pipe } from "effect"
pipe([1, 2, 3], Array.bindTo("x")) // => [{ x: 1 }, { x: 2 }, { x: 3 }]

These produce Reducer instances that combine arrays by concatenation, for use with APIs that accept a Reducer.

A Reducer that combines ReadonlyArray values by concatenation.

import { Array } from "effect"
const r = Array.getReadonlyReducerConcat<number>()
r.combine([1, 2], [3, 4]) // => [1, 2, 3, 4]

A Reducer that combines mutable Array values by concatenation.

import { Array } from "effect"
const r = Array.makeReducerConcat<number>()
r.combine([1, 2], [3, 4]) // => [1, 2, 3, 4]