Deep Signals

Deep structural reactivity for plain objects / arrays / Sets built on top of alien-signals.

Hooks for Svelte, Vue, and React.

Core idea: wrap a data tree in a Proxy that lazily creates per-property signals the first time you read them. Deep mutations emit batched patch objects (in a JSON-patch inspired style) that you can track with watch().

Features

  • Lazy: signals & child proxies created only when touched.
  • Deep: nested objects, arrays, Sets proxied.
  • Patch stream: microtask‑batched granular mutations (paths + op) for syncing external stores / framework adapters.
  • Getter => computed: property getters become derived (readonly) signals automatically.
  • Sets: add/delete/clear/... methods emit patches; object entries get synthetic stable ids.
  • Configurable synthetic IDs: custom property generator - the synthetic ID is used in the paths of patches to identify objects in sets. By default attached as @id property.
  • Read-only properties: protect specific properties from modification.
  • Shallow escape hatch: wrap sub-objects with shallow(obj) to track only reference replacement.

Install

pnpm add @ng-org/alien-deepsignals
# or
npm i @ng-org/alien-deepsignals

Quick start

import { deepSignal } from "@ng-org/alien-deepsignals";

const state = deepSignal({
  count: 0,
  user: { name: "Ada" },
  items: [{ id: "i1", qty: 1 }],
  settings: new Set(["dark"]),
});

state.count++; // mutate normally
state.user.name = "Grace"; // nested write
state.items.push({ id: "i2", qty: 2 });
state.settings.add("beta");

Frontend Hooks

We provide hooks for Svelte 3/4, Svelte 5, Vue, and React so that you can use deepSignal objects in your frontend framework. Modifying the object within those components works as usual, just that the component will rerender automatically when the object changed (by a modification in the component or a modification from elsewhere).

Note that you can pass existing deepSignal objects to useDeepSignal (that you are using elsewhere too, for example as shared state) as well as plain JavaScript objects (which are then wrapped).

You can (and are often advised to) use deepSignals as a shared state (and sub objects thereof) across components.

React

import { useDeepSignal } from "@ng-org/alien-deepsignals/react";
import { DeepSignal } from "@ng-org/alien-deepsignals";
import UserComponent from "./User.tsx";
import type { User } from "./types.ts";

function UserManager() {
  const users: DeepSignal<User[]> = useDeepSignal([{ username: "Bob" }]);

  return users.map((user) => <UserComponent key={user.id} user={user} />);
}

In child component User.tsx:

function UserComponent({ user }: { user: DeepSignal<User> }) {
  // Modifications here will trigger a re-render in the parent component
  // which updates this component.
  // For performance reasons, you are advised to call `useDeepSignal`
  // close to where its return value is used.
  return <input type="text" value={user.name} />;
}

Vue

In component UserManager.vue

<script setup lang="ts">
import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
import { DeepSignal } from "@ng-org/alien-deepsignals";
import UserComponent from "./User.vue";
import type { User } from "./types.ts";

const users: DeepSignal<User[]> = useDeepSignal([{ username: "Bob", id: 1 }]);
</script>

<template>
  <UserComponent v-for="user in users" :key="user.id" :user="user" />
</template>

In a child component, User.vue

<script setup lang="ts">
const props = defineProps<{
  user: DeepSignal<User>;
}>();

// The component only rerenders when user.name changes.
// It behaves the same as an object wrapped with `reactive()`
const user = props.user;
</script>
<template>
  <input type="text" v-model:value="user.name" />
</template>

Svelte 3 / 4

import { useDeepSignal } from "@ng-org/alien-deepsignals/svelte4";

// `users` is a store of type `{username: string}[]`
const users = useDeepSignal([{ username: "Bob" }]);

Svelte 5

import { useDeepSignal } from "@ng-org/alien-deepsignals/svelte";

// `users` is a rune of type `{username: string}[]`
const users = useDeepSignal([{ username: "Bob" }]);

Other Frameworks

Integrating new frontend frameworks is fairly easy. Get in touch if you are interested.

Reference

Interfaces

DeepPatchBatch

Defined in: sdk/js/alien-deepsignals/src/types.ts:23

Batched patch payload tagged with a monotonically increasing version.

Properties

patches

patches: DeepPatch[]

Defined in: sdk/js/alien-deepsignals/src/types.ts:25

version

version: number

Defined in: sdk/js/alien-deepsignals/src/types.ts:24


DeepSignalOptions

Defined in: sdk/js/alien-deepsignals/src/types.ts:42

Internal

Options to pass to deepSignal

Properties

propGenerator?

optional propGenerator: DeepSignalPropGenFn

Defined in: sdk/js/alien-deepsignals/src/types.ts:47

An optional function that is called when new objects are attached and that may return additional properties to be attached.

readOnlyProps?

optional readOnlyProps: string[]

Defined in: sdk/js/alien-deepsignals/src/types.ts:60

Optional: Properties that are made read-only in objects. Can only be attached by propGenerator or must already be member of the new object before attaching it.

replaceProxiesInBranchOnChange?

optional replaceProxiesInBranchOnChange: boolean

Defined in: sdk/js/alien-deepsignals/src/types.ts:66

If set to true, all proxies in the branch to a modified nested property are replaced. This has no effect except for equality checks (===). This is necessary for react to notice the change.

Default
false;
subscriberFactories?

optional subscriberFactories: Set<ExternalSubscriberFactory<any>>

Defined in: sdk/js/alien-deepsignals/src/types.ts:71

syntheticIdPropertyName?

optional syntheticIdPropertyName: string

Defined in: sdk/js/alien-deepsignals/src/types.ts:54

The property name which should be used as an object identifier in sets. You will see it when patches are generated with a path to an object in a set. The syntheticId will be a patch element then. Objects with existing properties matching syntheticIdPropertyName keep their values (not overwritten).


DeepSignalSet

Defined in: sdk/js/alien-deepsignals/src/types.ts:187

Type alias for DeepSignal<Set<T>> and reactive Set wrapper that accepts raw or proxied entries. Additionally it is decorated with DeepSignalSetProps.

Extends

Type Parameters

T

T

Properties

__raw__

__raw__: Set

Defined in: sdk/js/alien-deepsignals/src/types.ts:156

The original raw object.

Inherited from

DeepSignalObjectProps.__raw__

[toStringTag]

readonly [toStringTag]: string

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts:145

Inherited from

Set.[toStringTag]

size

readonly size: number

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts:112

Returns

the number of (unique) elements in Set.

Inherited from

Set.size

Methods

[dispose]()
Call Signature

[dispose](): void

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.disposable.d.ts:36

Returns

void

Inherited from

SetIterator.[dispose]

Call Signature

[dispose](): void

Defined in: node_modules/.pnpm/@types+node@22.18.3/node_modules/@types/node/compatibility/disposable.d.ts:9

Returns

void

Inherited from

SetIterator.[dispose]

[iterator]()

[iterator](): SetIterator<DeepSignal<T>>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:198

Iterates over values in the set.

Returns

SetIterator<DeepSignal<T>>

Inherited from

Set.[iterator]

add()

add(value): this

Defined in: sdk/js/alien-deepsignals/src/types.ts:192

Appends a new element with a specified value to the end of the Set.

Parameters
value

T | DeepSignal<T>

Returns

this

Overrides

Set.add

clear()

clear(): void

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts:95

Returns

void

Inherited from

Set.clear

delete()

delete(value): boolean

Defined in: sdk/js/alien-deepsignals/src/types.ts:193

Removes a specified value from the Set.

Parameters
value

T | DeepSignal<T>

Returns

boolean

Returns true if an element in the Set existed and has been removed, or false if the element does not exist.

Overrides

Set.delete

difference()

difference<U>(other): Set<DeepSignal<T>>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:48

Type Parameters
U

U

Parameters
other

ReadonlySetLike<U>

Returns

Set<DeepSignal<T>>

a new Set containing all the elements in this Set which are not also in the argument.

Inherited from

Set.difference

drop()

drop(count): IteratorObject<DeepSignal<T>, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:74

Creates an iterator whose values are the values from this iterator after skipping the provided count.

Parameters
count

number

The number of values to drop.

Returns

IteratorObject<DeepSignal<T>, undefined, unknown>

Inherited from

SetIterator.drop

entries()

entries(): SetIterator<[DeepSignal<T>, DeepSignal<T>]>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:203

Returns an iterable of [v,v] pairs for every value v in the set.

Returns

SetIterator<[DeepSignal<T>, DeepSignal<T>]>

Inherited from

Set.entries

every()

every(predicate): boolean

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:122

Determines whether all the members of this iterator satisfy the specified test.

Parameters
predicate

(value, index) => unknown

A function that accepts up to two arguments. The every method calls the predicate function for each element in this iterator until the predicate returns false, or until the end of this iterator.

Returns

boolean

Inherited from

SetIterator.every

filter()
Call Signature

filter<S>(predicate): IteratorObject<S, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:56

Creates an iterator whose values are those from this iterator for which the provided predicate returns true.

Type Parameters
S

S

Parameters
predicate

(value, index) => value is S

A function that accepts up to two arguments to be used to test values from the underlying iterator.

Returns

IteratorObject<S, undefined, unknown>

Inherited from

SetIterator.filter

Call Signature

filter(predicate): IteratorObject<DeepSignal<T>, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:62

Creates an iterator whose values are those from this iterator for which the provided predicate returns true.

Parameters
predicate

(value, index) => unknown

A function that accepts up to two arguments to be used to test values from the underlying iterator.

Returns

IteratorObject<DeepSignal<T>, undefined, unknown>

Inherited from

SetIterator.filter

find()
Call Signature

find<S>(predicate): S | undefined

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:131

Returns the value of the first element in this iterator where predicate is true, and undefined otherwise.

Type Parameters
S

S

Parameters
predicate

(value, index) => value is S

find calls predicate once for each element of this iterator, in order, until it finds one where predicate returns true. If such an element is found, find immediately returns that element value. Otherwise, find returns undefined.

Returns

S | undefined

Inherited from

SetIterator.find

Call Signature

find(predicate): DeepSignal<T> | undefined

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:132

Parameters
predicate

(value, index) => unknown

Returns

DeepSignal<T> | undefined

Inherited from

SetIterator.find

first()

first(): T extends object ? DeepSignal<T> : T | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:164

Get the element that was first inserted into the set.

Returns

T extends object ? DeepSignal<T> : T | undefined

Inherited from

DeepSignalSetProps.first

flatMap()

flatMap<U>(callback): IteratorObject<U, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:80

Creates an iterator whose values are the result of applying the callback to the values from this iterator and then flattening the resulting iterators or iterables.

Type Parameters
U

U

Parameters
callback

(value, index) => Iterator<U, unknown, undefined> | Iterable<U, unknown, undefined>

A function that accepts up to two arguments to be used to transform values from the underlying iterator into new iterators or iterables to be flattened into the result.

Returns

IteratorObject<U, undefined, unknown>

Inherited from

SetIterator.flatMap

forEach()
Call Signature

forEach(callbackfn, thisArg?): void

Defined in: sdk/js/alien-deepsignals/src/types.ts:195

Executes a provided function once per each value in the Set object, in insertion order.

Parameters
callbackfn

(value, value2, set) => void

thisArg?

any

Returns

void

Overrides

Set.forEach

Call Signature

forEach(callbackfn, thisArg?): void

Defined in: sdk/js/alien-deepsignals/src/types.ts:203

Executes a provided function once per each value in the Set object, in insertion order.

Parameters
callbackfn

(value, index) => void

thisArg?

any

Returns

void

Overrides

Set.forEach

getBy()

getBy(graphIri, subjectIri): DeepSignal<T> | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:180

Retrieve an object from the Set by its @graph and @id.

Parameters
graphIri

string

The @graph NURI of the object.

subjectIri

string

The @subject IRI of the object.

Returns

DeepSignal<T> | undefined

The proxied entry if found, undefined otherwise.

Inherited from

DeepSignalSetProps.getBy

getById()

getById(id): DeepSignal<T> | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:171

Retrieve an entry from the Set by its synthetic set ID.

Parameters
id

The synthetic ID (string or number) assigned to the entry.

string | number

Returns

DeepSignal<T> | undefined

The proxied entry if found, undefined otherwise.

Inherited from

DeepSignalSetProps.getById

has()

has(value): boolean

Defined in: sdk/js/alien-deepsignals/src/types.ts:194

Parameters
value

T | DeepSignal<T>

Returns

boolean

a boolean indicating whether an element with the specified value exists in the Set or not.

Overrides

Set.has

intersection()

intersection<U>(other): Set<DeepSignal<T> & U>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:44

Type Parameters
U

U

Parameters
other

ReadonlySetLike<U>

Returns

Set<DeepSignal<T> & U>

a new Set containing all the elements which are both in this Set and in the argument.

Inherited from

Set.intersection

isDisjointFrom()

isDisjointFrom(other): boolean

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:64

Parameters
other

ReadonlySetLike<unknown>

Returns

boolean

a boolean indicating whether this Set has no elements in common with the argument.

Inherited from

Set.isDisjointFrom

isSubsetOf()

isSubsetOf(other): boolean

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:56

Parameters
other

ReadonlySetLike<unknown>

Returns

boolean

a boolean indicating whether all the elements in this Set are also in the argument.

Inherited from

Set.isSubsetOf

isSupersetOf()

isSupersetOf(other): boolean

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:60

Parameters
other

ReadonlySetLike<unknown>

Returns

boolean

a boolean indicating whether all the elements in the argument are also in this Set.

Inherited from

Set.isSupersetOf

keys()

keys(): SetIterator<DeepSignal<T>>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:208

Despite its name, returns an iterable of the values in the set.

Returns

SetIterator<DeepSignal<T>>

Inherited from

Set.keys

map()

map<U>(callbackfn): IteratorObject<U, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:50

Creates an iterator whose values are the result of applying the callback to the values from this iterator.

Type Parameters
U

U

Parameters
callbackfn

(value, index) => U

A function that accepts up to two arguments to be used to transform values from the underlying iterator.

Returns

IteratorObject<U, undefined, unknown>

Inherited from

SetIterator.map

next()

next(…__namedParameters): IteratorResult<DeepSignal<T>, undefined>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:43

Parameters
__namedParameters

[] | [unknown]

Returns

IteratorResult<DeepSignal<T>, undefined>

Inherited from

SetIterator.next

reduce()
Call Signature

reduce(callbackfn): DeepSignal

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:87

Calls the specified callback function for all the elements in this iterator. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.

Parameters
callbackfn

(previousValue, currentValue, currentIndex) => DeepSignal

A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the iterator.

Returns

DeepSignal

Inherited from

SetIterator.reduce

Call Signature

reduce(callbackfn, initialValue): DeepSignal

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:88

Parameters
callbackfn

(previousValue, currentValue, currentIndex) => DeepSignal

initialValue

DeepSignal

Returns

DeepSignal

Inherited from

SetIterator.reduce

Call Signature

reduce<U>(callbackfn, initialValue): U

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:95

Calls the specified callback function for all the elements in this iterator. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.

Type Parameters
U

U

Parameters
callbackfn

(previousValue, currentValue, currentIndex) => U

A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the iterator.

initialValue

U

If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of a value from the iterator.

Returns

U

Inherited from

SetIterator.reduce

return()?

optional return(value?): IteratorResult<DeepSignal<T>, undefined>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:44

Parameters
value?

undefined

Returns

IteratorResult<DeepSignal<T>, undefined>

Inherited from

SetIterator.return

some()

some(predicate): boolean

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:114

Determines whether the specified callback function returns true for any element of this iterator.

Parameters
predicate

(value, index) => unknown

A function that accepts up to two arguments. The some method calls the predicate function for each element in this iterator until the predicate returns a value true, or until the end of the iterator.

Returns

boolean

Inherited from

SetIterator.some

symmetricDifference()

symmetricDifference<U>(other): Set<DeepSignal<T> | U>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:52

Type Parameters
U

U

Parameters
other

ReadonlySetLike<U>

Returns

Set<DeepSignal<T> | U>

a new Set containing all the elements which are in either this Set or in the argument, but not in both.

Inherited from

Set.symmetricDifference

take()

take(limit): IteratorObject<DeepSignal<T>, undefined, unknown>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:68

Creates an iterator whose values are the values from this iterator, stopping once the provided limit is reached.

Parameters
limit

number

The maximum number of values to yield.

Returns

IteratorObject<DeepSignal<T>, undefined, unknown>

Inherited from

SetIterator.take

throw()?

optional throw(e?): IteratorResult<DeepSignal<T>, undefined>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:45

Parameters
e?

any

Returns

IteratorResult<DeepSignal<T>, undefined>

Inherited from

SetIterator.throw

toArray()

toArray(): DeepSignal<T>[]

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.iterator.d.ts:100

Creates a new array from the values yielded by this iterator.

Returns

DeepSignal<T>[]

Inherited from

SetIterator.toArray

union()

union<U>(other): Set<DeepSignal<T> | U>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.collection.d.ts:40

Type Parameters
U

U

Parameters
other

ReadonlySetLike<U>

Returns

Set<DeepSignal<T> | U>

a new Set containing all the elements in this Set and also all the elements in the argument.

Inherited from

Set.union

values()

values(): SetIterator<DeepSignal<T>>

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts:213

Returns an iterable of values in the set.

Returns

SetIterator<DeepSignal<T>>

Inherited from

Set.values


WatchOptions

Defined in: sdk/js/alien-deepsignals/src/watch.ts:27

Properties

immediate?

optional immediate: boolean

Defined in: sdk/js/alien-deepsignals/src/watch.ts:29

True, if the callback should be run immediately after watch was called.

Default
false;
once?

optional once: boolean

Defined in: sdk/js/alien-deepsignals/src/watch.ts:31

True, if the watcher should be unsubscribed after the first event.

Default
false;
triggerInstantly?

optional triggerInstantly: boolean

Defined in: sdk/js/alien-deepsignals/src/watch.ts:38

If true, triggers watch callback instantly after changes to the signal object. Otherwise, changes are batched and the watch callback is triggered in a microtask. This is useful for frontends like React where modifications on the changed input in a separate (microtask) will cause the cursor in input elements to reset.


WatchPatchEvent

Defined in: sdk/js/alien-deepsignals/src/watch.ts:41

Type Parameters

T

T extends object

Properties

newValue

newValue: DeepSignal<T>

Defined in: sdk/js/alien-deepsignals/src/watch.ts:47

The current value of the signal

patches

patches: DeepPatch[]

Defined in: sdk/js/alien-deepsignals/src/watch.ts:43

The changes made

version?

optional version: number

Defined in: sdk/js/alien-deepsignals/src/watch.ts:45

The version if triggerInstantly is not true.

Type Aliases

ComputedSignal

ComputedSignal<T> = ReturnType<typeof computed>

Defined in: sdk/js/alien-deepsignals/src/types.ts:150

Type Parameters

T

T = any


DeepPatch

DeepPatch = object & { op: "add"; type?: "object" | "set"; value?: any; } | { op: "remove"; type?: "set"; value?: any; }

Defined in: sdk/js/alien-deepsignals/src/types.ts:15

Deep mutation emitted from a deepSignal root.

Type Declaration

path

path: (string | number)[]


DeepSignal

DeepSignal<T> = T extends Function ? T : T extends string | number | boolean ? T : T extends DeepSignalObjectProps<any> | DeepSignalObjectProps<any>[] ? T : T extends infer I[] ? DeepSignal<I>[] : T extends Set<infer S> ? DeepSignalSet<S> : T extends object ? DeepSignalObject<T> : T

Defined in: sdk/js/alien-deepsignals/src/types.ts:214

The object returned by the deepSignal function. It is decorated with utility functions for sets, see DeepSignalSetProps and a __raw__ prop to get the underlying non-reactive object.

Type Parameters

T

T


DeepSignalObject

DeepSignalObject<T> = { [K in keyof T]: DeepSignal<T[K]> }

Defined in: sdk/js/alien-deepsignals/src/types.ts:228

Type Parameters

T

T extends object


DeepSignalPropGenFn()

DeepSignalPropGenFn = (props) => object

Defined in: sdk/js/alien-deepsignals/src/types.ts:106

Internal

The propGenerator function is called when a new object is added to the deep signal tree.

Parameters

props
inSet

boolean

Whether the object is being added to a Set (true) or not (false)

object

any

The newly added object itself

path

(string | number)[]

The path of the newly added object.

Returns

extraProps?

optional extraProps: Record<string, unknown>

Additional properties to be added to the object (overwriting existing ones).

syntheticId?

optional syntheticId: string | number

A custom identifier for the object (used in Set entry paths and optionally as a property).

Example

let counter = 0;
const state = deepSignal(
  { items: new Set() },
  {
    propGenerator: ({ path, inSet, object }) => ({
      syntheticId: inSet
        ? `urn:item:${++counter}`
        : `urn:obj:${path.join("-")}`,
      extraProps: { createdAt: new Date().toISOString() },
    }),
    syntheticIdPropertyName: "@id",
  },
);

state.items.add({ name: "Item 1" });
// Attaches `{ name: "Item 1", `@id`: "urn:item:1", createdAt: <current date>`

state.foo = { bar: 42 };
// Attaches `{bar: 42, "@id": "urn:obj:foo", createdAt: <current date>}`

DeepSignalSetProps

DeepSignalSetProps<T> = object

Defined in: sdk/js/alien-deepsignals/src/types.ts:162

Utility functions for sets.

Extended by

Type Parameters

T

T

Methods

first()

first(): T extends object ? DeepSignal<T> : T | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:164

Get the element that was first inserted into the set.

Returns

T extends object ? DeepSignal<T> : T | undefined

getBy()

getBy(graphIri, subjectIri): DeepSignal<T> | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:180

Retrieve an object from the Set by its @graph and @id.

Parameters
graphIri

string

The @graph NURI of the object.

subjectIri

string

The @subject IRI of the object.

Returns

DeepSignal<T> | undefined

The proxied entry if found, undefined otherwise.

getById()

getById(id): DeepSignal<T> | undefined

Defined in: sdk/js/alien-deepsignals/src/types.ts:171

Retrieve an entry from the Set by its synthetic set ID.

Parameters
id

The synthetic ID (string or number) assigned to the entry.

string | number

Returns

DeepSignal<T> | undefined

The proxied entry if found, undefined otherwise.


ExternalSubscriberFactory()

ExternalSubscriberFactory<T> = () => object

Defined in: sdk/js/alien-deepsignals/src/types.ts:74

Type Parameters

T

T = any

Returns

object

onGet()

onGet: () => void

Returns

void

onSet()

onSet: (newVal) => void

Parameters
newVal

T

Returns

void


MaybeSignal

MaybeSignal<T> = T | ReturnType<typeof alienSignal>

Defined in: sdk/js/alien-deepsignals/src/types.ts:235

Union allowing a plain value or a writable signal wrapping that value.

Type Parameters

T

T = any


MaybeSignalOrComputed

MaybeSignalOrComputed<T> = MaybeSignal<T> | () => T

Defined in: sdk/js/alien-deepsignals/src/types.ts:237

Union allowing value, writable signal, computed signal or plain getter function.

Type Parameters

T

T = any


RegisterCleanup()

RegisterCleanup = (cleanupFn) => void

Defined in: sdk/js/alien-deepsignals/src/watch.ts:25

Parameters

cleanupFn

() => void

Returns

void


SignalLike

SignalLike<T> = WritableSignal<T> | ComputedSignal<T>

Defined in: sdk/js/alien-deepsignals/src/types.ts:151

Type Parameters

T

T = any


UnwrapDeepSignal

UnwrapDeepSignal<T> = T extends DeepSignal<infer S> ? S : T

Defined in: sdk/js/alien-deepsignals/src/types.ts:232

Type Parameters

T

T


WatchPatchCallback()

WatchPatchCallback<T> = (event) => void

Defined in: sdk/js/alien-deepsignals/src/watch.ts:50

Type Parameters

T

T extends object

Parameters

event

WatchPatchEvent<T>

Returns

void

Variables

alienSignal()

const alienSignal: {<T>(): {(): T | undefined; (value): void; }; <T>(initialValue): {(): T; (value): void; }; } = alienSignal_

Defined in: sdk/js/alien-deepsignals/src/core.ts:99

Re-export of alien-signals signal function which creates a basic signal.

Call Signature

<T>(): {(): T | undefined; (value): void; }

Type Parameters
T

T

Returns

(): T | undefined

Returns

T | undefined

(value): void

Parameters
value

T | undefined

Returns

void

Call Signature

<T>(initialValue): {(): T; (value): void; }

Type Parameters
T

T

Parameters
initialValue

T

Returns

(): T

Returns

T

(value): void

Parameters
value

T

Returns

void


computed()

const computed: <T>(getter) => () => T = alienComputed

Defined in: sdk/js/alien-deepsignals/src/core.ts:94

Re-export of alien-signals computed function.

Use the computed() function to create lazy derived signals that automatically track their dependencies and recompute only when needed.

Key features:

  • Lazy evaluation: The computation runs only when you actually read the computed value. If you never access fullName(), the concatenation never happens—no wasted CPU cycles.
  • Automatic caching: Once computed, the result is cached until a dependency changes. Multiple reads return the cached value without re-running the getter.
  • Fine-grained reactivity: Only recomputes when its tracked dependencies change. Unrelated state mutations don’t trigger unnecessary recalculation.
  • Composable: Computed signals can depend on other computed signals, forming efficient dependency chains.

Type Parameters

T

T

Parameters

getter

(previousValue?) => T

Returns

(): T

Returns

T

Example

import { computed } from "@ng-org/alien-deepsignals";

const state = deepSignal({
  firstName: "Ada",
  lastName: "Lovelace",
  items: [1, 2, 3],
});

// Create a computed signal that derives from reactive state
const fullName = computed(() => `${state.firstName} ${state.lastName}`);

console.log(fullName()); // "Ada Lovelace" - computes on first access

state.firstName = "Grace";
console.log(fullName()); // "Grace Lovelace" - recomputes automatically

// Expensive computation only runs when accessed and dependencies change
const expensiveResult = computed(() => {
  console.log("Computing...");
  return state.items.reduce((sum, n) => sum + n * n, 0);
});

// No computation happens yet!
state.items.push(4);
// Still no computation...

console.log(expensiveResult()); // "Computing..." + result
console.log(expensiveResult()); // Cached, no log
state.items.push(5);
console.log(expensiveResult()); // "Computing..." again (dependency changed)

effect()

const effect: (fn) => () => void = alienEffect

Defined in: sdk/js/alien-deepsignals/src/core.ts:107

Re-export of alien-signals effect function.

Callback reruns on every signal modification that is used within its callback.

Parameters

fn

() => void

Returns

(): void

Returns

void

Functions

addWithId()

addWithId<T>(set, entry, id): T

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1439

Convenience helper to add an entry to a proxied Set with a pre-defined synthetic ID.

Type Parameters

T

T

Parameters

set

Set<T>

entry

T

id

string | number

Returns

T


batch()

batch<T>(fn): T

Defined in: sdk/js/alien-deepsignals/src/core.ts:34

Execute multiple signal writes in a single batched update frame. All downstream computed/effect re-evaluations are deferred until the function exits.

IMPORTANT: The callback must be synchronous. If it returns a Promise the batch will still end immediately after scheduling, possibly causing mid-async flushes.

Type Parameters

T

T

Parameters

fn

() => T

Returns

T

Example

batch(() => {
  count(count() + 1);
  other(other() + 2);
}); // effects observing both run only once

deepSignal()

deepSignal<T>(input, options?): DeepSignal<T>

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1328

MAIN ENTRY POINT to create a deep reactive proxy for objects, arrays or Sets.

If input is a deepSignal already and options are provided, the added subscriberFactories are joined with the existing ones and replaceProxiesInBranchOnChange is or-ed with the current value.

Type Parameters

T

T extends object

Parameters

input

T

options?

DeepSignalOptions

Returns

DeepSignal<T>

Throws

if provided with unsupported input types.


getRaw()

getRaw<T>(value): any

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1455

Get the original, raw value of a deep signal.

Type Parameters

T

T extends object

Parameters

value

T | DeepSignal<T>

Returns

any


isDeepSignal()

isDeepSignal(value): value is any

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1314

Runtime guard that checks whether a value is a deepSignal proxy.

Parameters

value

unknown

Returns

value is any


shallow()

shallow<T>(obj): T

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1426

Mark an object so deepSignal skips proxying it (shallow boundary).

Type Parameters

T

T extends object

Parameters

obj

T

Returns

T

Example

import { shallow } from "alien-deepsignals";
state.config = shallow({ huge: { blob: true } });

subscribeDeepMutations()

subscribeDeepMutations(root, cb, triggerInstantly?): () => void

Defined in: sdk/js/alien-deepsignals/src/deepSignal.ts:1378

Low-level function, you should probably use watch instead.

Register a deep mutation subscriber for the provided root or proxy.

Parameters

root

symbol | object

cb

DeepPatchJITSubscriber | DeepPatchSubscriber

triggerInstantly?

boolean = false

Returns

(): void

Returns

void


watch()

watch<T>(source, callback, options?): object

Defined in: sdk/js/alien-deepsignals/src/watch.ts:89

Watch for changes to a deepSignal.

Whenever a change is made, callback is called with the patches describing the change and the new value. If you set triggerInstantly, the callback is called on every property change. If not, all changes are aggregated and callback is called in a microtask when the current task finishes, e.g. await is called (meaning it supports batching).

When objects are added to Sets, their synthetic ID (usually @id) becomes part of the patch path. This allows patches to uniquely identify which Set entry is being mutated.

const state = deepSignal(
    { s: new Set() },
    { ...}
);

watch(state, ({ patches }) => {
    console.log(JSON.stringify(patches));
});

state.s.add({ data: "test" });
// Will log:
// [
//   {"path":["s","did:ng:o:123"],"op":"add","type":"object"},
//   {"path":["s","did:ng:o:123","@id"],"op":"add","value":"did:ng:o:123"},
//   {"path":["s","did:ng:o:123","data"],"op":"add","value":"test"}
// ]

state.s.getById("did:ng:o:123")!.data = "new value"
// Will log:
// [
//   {"path":["s","did:ng:o:123","data"],"op":"add","value":"new value"}
// ]

Type Parameters

T

T extends object

Parameters

source

DeepSignalSet<T> | DeepSignalObject<T> | DeepSignal<T>

callback

WatchPatchCallback<T>

options?

WatchOptions = {}

Returns

object

registerCleanup

registerCleanup: RegisterCleanup

stopListening()

stopListening: () => void

Returns

void