<const Elements extends ReadonlyArray<Equivalence<any>>>(
elements: Elements
): Equivalence<{
readonly [I in keyof Elements]: [Elements[I]] extends [
Equivalence<infer A>
]
? A
: never
}>Creates an equivalence for tuples with heterogeneous element types.
When to use
Use when you need an Equivalence for fixed-length tuples with per-position
equivalences.
Details
Tuples must have the same length; different lengths are never equivalent.
Each equivalence is applied to the corresponding element position. The result
returns true only if all elements are equivalent according to their
respective equivalences, and it also satisfies reflexive, symmetric, and
transitive properties.
Example (Comparing homogeneous tuples)
import { Equivalence } from "effect"
const stringTupleEq = Equivalence.Tuple([
Equivalence.strictEqual<string>(),
Equivalence.strictEqual<string>(),
Equivalence.strictEqual<string>()
])
const tuple1 = ["hello", "world", "test"] as const
const tuple2 = ["hello", "world", "test"] as const
const tuple3 = ["hello", "world", "different"] as const
console.log(stringTupleEq(tuple1, tuple2)) // true
console.log(stringTupleEq(tuple1, tuple3)) // false (different third element)Example (Comparing tuples with custom equivalences)
import { Equivalence } from "effect"
const caseInsensitive = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(s: string) => s.toLowerCase()
)
const customTupleEq = Equivalence.Tuple([
caseInsensitive,
caseInsensitive,
caseInsensitive
])
console.log(
customTupleEq(["Hello", "World", "Test"], ["HELLO", "WORLD", "TEST"])
) // trueexport function function Tuple<
Elements extends ReadonlyArray<Equivalence<any>>
>(
elements: Elements
): Equivalence<{
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}>
Creates an equivalence for tuples with heterogeneous element types.
When to use
Use when you need an Equivalence for fixed-length tuples with per-position
equivalences.
Details
Tuples must have the same length; different lengths are never equivalent.
Each equivalence is applied to the corresponding element position. The result
returns true only if all elements are equivalent according to their
respective equivalences, and it also satisfies reflexive, symmetric, and
transitive properties.
Example (Comparing homogeneous tuples)
import { Equivalence } from "effect"
const stringTupleEq = Equivalence.Tuple([
Equivalence.strictEqual<string>(),
Equivalence.strictEqual<string>(),
Equivalence.strictEqual<string>()
])
const tuple1 = ["hello", "world", "test"] as const
const tuple2 = ["hello", "world", "test"] as const
const tuple3 = ["hello", "world", "different"] as const
console.log(stringTupleEq(tuple1, tuple2)) // true
console.log(stringTupleEq(tuple1, tuple3)) // false (different third element)
Example (Comparing tuples with custom equivalences)
import { Equivalence } from "effect"
const caseInsensitive = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(s: string) => s.toLowerCase()
)
const customTupleEq = Equivalence.Tuple([
caseInsensitive,
caseInsensitive,
caseInsensitive
])
console.log(
customTupleEq(["Hello", "World", "Test"], ["HELLO", "WORLD", "TEST"])
) // true
Tuple<const function (type parameter) Elements in Tuple<const Elements extends ReadonlyArray<Equivalence<any>>>(elements: Elements): Equivalence<{ readonly [I in keyof Elements]: [Elements[I]] extends [Equivalence<infer A>] ? A : never; }>Elements extends interface ReadonlyArray<T>ReadonlyArray<type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<any>>>(
elements: const Elements extends ReadonlyArray<Equivalence<any>>elements: function (type parameter) Elements in Tuple<const Elements extends ReadonlyArray<Equivalence<any>>>(elements: Elements): Equivalence<{ readonly [I in keyof Elements]: [Elements[I]] extends [Equivalence<infer A>] ? A : never; }>Elements
): type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<{ readonly [function (type parameter) II in keyof function (type parameter) Elements in Tuple<const Elements extends ReadonlyArray<Equivalence<any>>>(elements: Elements): Equivalence<{ readonly [I in keyof Elements]: [Elements[I]] extends [Equivalence<infer A>] ? A : never; }>Elements]: [function (type parameter) Elements in Tuple<const Elements extends ReadonlyArray<Equivalence<any>>>(elements: Elements): Equivalence<{ readonly [I in keyof Elements]: [Elements[I]] extends [Equivalence<infer A>] ? A : never; }>Elements[function (type parameter) II]] extends [type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<infer function (type parameter) AA>] ? function (type parameter) AA : never }> {
return const make: <A>(
isEquivalent: (self: A, that: A) => boolean
) => Equivalence<A>
Creates a custom equivalence relation with an optimized reference equality check.
When to use
Use when you need an equality rule that the built-in instances and input
mapping helpers cannot express, and you can provide a law-abiding comparison.
Details
The returned equivalence first checks reference equality (===) for
performance. If the values are not the same reference, it falls back to the
provided equivalence function, which must satisfy reflexive, symmetric, and
transitive properties.
Example (Case-insensitive string equivalence)
import { Equivalence } from "effect"
const caseInsensitive = Equivalence.make<string>((a, b) =>
a.toLowerCase() === b.toLowerCase()
)
console.log(caseInsensitive("Hello", "HELLO")) // true
console.log(caseInsensitive("foo", "bar")) // false
// Same reference optimization
const str = "test"
console.log(caseInsensitive(str, str)) // true (fast path)
Example (Comparing numbers with tolerance)
import { Equivalence } from "effect"
const tolerance = Equivalence.make<number>((a, b) => Math.abs(a - b) < 0.0001)
console.log(tolerance(1.0, 1.001)) // false
console.log(tolerance(1.0, 1.00001)) // true
make((self: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
self, that: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
that) => {
if (self: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
self.ReadonlyArray<any>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length !== that: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
that.ReadonlyArray<any>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length) {
return false
}
for (let let i: numberi = 0; let i: numberi < self: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
self.ReadonlyArray<any>.length: numberGets the length of the array. This is a number one higher than the highest element defined in an array.
length; let i: numberi++) {
if (!elements: const Elements extends ReadonlyArray<Equivalence<any>>elements[let i: numberi](self: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
self[let i: numberi], that: {
readonly [I in keyof Elements]: [
Elements[I]
] extends [Equivalence<infer A>]
? A
: never
}
that[let i: numberi])) {
return false
}
}
return true
})
}