<O extends object>(that: O): <S extends object>(self: S) => Assign<S, O>
<O extends object, S extends object>(self: S, that: O): Assign<S, O>Merges two structs into a new struct. When both structs share a key, the
value from that (the second struct) wins.
When to use
Use when you want { ...self, ...that } with proper types.
Details
The result type is Simplify<Assign<S, O>>.
Example (Merging structs with overlapping keys)
import { pipe, Struct } from "effect"
const defaults = { theme: "light", lang: "en" }
const overrides = { theme: "dark", fontSize: 14 }
const config = pipe(defaults, Struct.assign(overrides))
console.log(config) // { theme: "dark", lang: "en", fontSize: 14 }export const const assign: {
<O extends object>(that: O): <S extends object>(
self: S
) => Assign<S, O>
<O extends object, S extends object>(
self: S,
that: O
): Assign<S, O>
}
Merges two structs into a new struct. When both structs share a key, the
value from that (the second struct) wins.
When to use
Use when you want { ...self, ...that } with proper types.
Details
The result type is Simplify<Assign<S, O>>.
Example (Merging structs with overlapping keys)
import { pipe, Struct } from "effect"
const defaults = { theme: "light", lang: "en" }
const overrides = { theme: "dark", fontSize: 14 }
const config = pipe(defaults, Struct.assign(overrides))
console.log(config) // { theme: "dark", lang: "en", fontSize: 14 }
assign: {
<function (type parameter) O in <O extends object>(that: O): <S extends object>(self: S) => Assign<S, O>O extends object>(that: O extends objectthat: function (type parameter) O in <O extends object>(that: O): <S extends object>(self: S) => Assign<S, O>O): <function (type parameter) S in <S extends object>(self: S): Assign<S, O>S extends object>(self: S extends objectself: function (type parameter) S in <S extends object>(self: S): Assign<S, O>S) => type Assign<T, U> = {
[K in keyof (keyof T & keyof U extends never
? T & U
: Omit<T, keyof T & keyof U> & U)]: (keyof T &
keyof U extends never
? T & U
: Omit<T, keyof T & keyof U> & U)[K]
}
Merges two object types with properties from U taking precedence over T
on overlapping keys (like Object.assign at the type level).
When to use
Use when you need the type-level equivalent of { ...T, ...U }.
Details
When no keys overlap, this returns a simple intersection for efficiency.
When keys overlap, the type from U wins.
Example (Merging two types with overlapping keys)
import type { Struct } from "effect"
type A = { a: string; b: number }
type B = { b: boolean; c: string }
type Merged = Struct.Assign<A, B>
// { a: string; b: boolean; c: string }
Assign<function (type parameter) S in <S extends object>(self: S): Assign<S, O>S, function (type parameter) O in <O extends object>(that: O): <S extends object>(self: S) => Assign<S, O>O>
<function (type parameter) O in <O extends object, S extends object>(self: S, that: O): Assign<S, O>O extends object, function (type parameter) S in <O extends object, S extends object>(self: S, that: O): Assign<S, O>S extends object>(self: S extends objectself: function (type parameter) S in <O extends object, S extends object>(self: S, that: O): Assign<S, O>S, that: O extends objectthat: function (type parameter) O in <O extends object, S extends object>(self: S, that: O): Assign<S, O>O): type Assign<T, U> = {
[K in keyof (keyof T & keyof U extends never
? T & U
: Omit<T, keyof T & keyof U> & U)]: (keyof T &
keyof U extends never
? T & U
: Omit<T, keyof T & keyof U> & U)[K]
}
Merges two object types with properties from U taking precedence over T
on overlapping keys (like Object.assign at the type level).
When to use
Use when you need the type-level equivalent of { ...T, ...U }.
Details
When no keys overlap, this returns a simple intersection for efficiency.
When keys overlap, the type from U wins.
Example (Merging two types with overlapping keys)
import type { Struct } from "effect"
type A = { a: string; b: number }
type B = { b: boolean; c: string }
type Merged = Struct.Assign<A, B>
// { a: string; b: boolean; c: string }
Assign<function (type parameter) S in <O extends object, S extends object>(self: S, that: O): Assign<S, O>S, function (type parameter) O in <O extends object, S extends object>(self: S, that: O): Assign<S, O>O>
} = dual<(...args: Array<any>) => any, <O extends object, S extends object>(self: S, that: O) => S & O>(arity: 2, body: <O extends object, S extends object>(self: S, that: O) => S & O): ((...args: Array<any>) => any) & (<O extends object, S extends object>(self: S, that: O) => S & O) (+1 overload)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.
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)
console.log(sum(2, 3)) // 5
console.log(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)
console.log(sum(2, 3)) // 5
console.log(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
)
console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5
dual(
2,
<function (type parameter) O in <O extends object, S extends object>(self: S, that: O): S & OO extends object, function (type parameter) S in <O extends object, S extends object>(self: S, that: O): S & OS extends object>(self: S extends objectself: function (type parameter) S in <O extends object, S extends object>(self: S, that: O): S & OS, that: O extends objectthat: function (type parameter) O in <O extends object, S extends object>(self: S, that: O): S & OO) => {
return { ...self: S extends objectself, ...that: O extends objectthat }
}
)