Skip to main content

patch

@rotorsoft/act-root


@rotorsoft/act-root / act/src / patch

Function: patch()

patch<S>(original, patches): Readonly<S>

Defined in: libs/act/src/utils.ts:131

Immutably applies patches to a state object, creating a new copy.

This function performs deep merging for plain objects while preserving immutability. Special types (Arrays, Dates, Maps, etc.) are replaced entirely rather than merged. Setting a property to undefined or null removes it from the resulting object.

Used internally by the framework to apply event patches to state, but can also be used directly for state transformations.

Merging rules:

  • Plain objects: Deep merge recursively
  • Arrays, Dates, RegExp, Maps, Sets, TypedArrays: Replace entirely
  • undefined or null values: Delete the property
  • Primitives: Replace with patch value

Type Parameters

S

S extends Schema

Parameters

original

Readonly<S>

The original state object to patch

patches

Readonly<Patch<S>>

The patches to apply (partial state)

Returns

Readonly<S>

A new state object with patches applied

Examples

import { patch } from "@rotorsoft/act";

const state = { count: 0, name: "Alice" };
const updated = patch(state, { count: 5 });
// Result: { count: 5, name: "Alice" }
// Original unchanged: { count: 0, name: "Alice" }
const state = {
user: { id: 1, name: "Alice", email: "alice@example.com" },
settings: { theme: "dark" }
};

const updated = patch(state, {
user: { email: "newemail@example.com" }
});
// Result: {
// user: { id: 1, name: "Alice", email: "newemail@example.com" },
// settings: { theme: "dark" }
// }
const state = { count: 5, temp: "value", flag: true };

const updated = patch(state, {
temp: undefined, // Delete temp
flag: null // Delete flag
});
// Result: { count: 5 }
const state = { items: [1, 2, 3], meta: { count: 3 } };

const updated = patch(state, {
items: [4, 5] // Arrays are replaced, not merged
});
// Result: { items: [4, 5], meta: { count: 3 } }
import { state } from "@rotorsoft/act";
import { z } from "zod";

const Counter = state({ Counter: z.object({ count: z.number() }) })
.init(() => ({ count: 0 }))
.emits({ Incremented: z.object({ by: z.number() }) })
.patch({
Incremented: (event, state) => {
// patch() is called internally here
return { count: state.count + event.data.by };
}
});

See

Patch for the patch type definition