Object.ts is a lightweight library providing reactive primitives and object utilities for JavaScript. It is a minor sibling of Uniform.TS, originally created in early 2024 and partially revisited in 2025. The library is primarily used in internal projects and is designed to be compatible with modern reactive libraries.
- Non-intrusive subscriptions: Subscribers do not retain references to target objects.
- Efficient reactivity: Triggers only on actual value changes.
- Compatibility: Works with recent versions of popular reactive libraries.
-
makeReactive(initial)Creates a reactive primitive from an existing object. -
subscribe(obj, callback)Subscribes to changes in an observable object,Set, orMap.- Supports
[obj, key]to subscribe to a specific property. - Returns an unsubscribe function.
- Supports
-
ref(initial)Creates an observable reference with avalueproperty. -
computed(sub)Similar toref, but computes its value from a reactive source.- Setting the value has no effect on the source.
-
conditional(cond, ifTrue, ifFalse)Reactive value that switches betweenifTrueandifFalsebased oncond.value.
npm i @fest-lib/objectimport {
ref,
numberRef,
stringRef,
booleanRef,
autoRef,
promised,
makeReactive,
subscribe,
observe,
unsubscribe,
derivate,
bindBy,
safe
} from "@fest-lib/object";const state = makeReactive({ count: 0, user: { name: "Ada" } });
const stop = subscribe(state, (value, prop) => {
console.log("changed:", prop, value[prop as keyof typeof value]);
});
state.count = 1;
stop?.();const n = numberRef(0);
const s = stringRef("hello");
const b = booleanRef(false);
n.value++; // 1
s.value = s + "!"; // "hello!"
b.value = 1; // true (truthy coercion)const r1 = autoRef(true); // booleanRef
const r2 = autoRef(42); // numberRef
const r3 = autoRef("hi"); // stringRef
const r4 = ref<any>({ a: 1 });
const later = promised(fetch("/api").then(r => r.status));
subscribe(later, () => console.log("ready:", later.value));const list = makeReactive([1, 2, 3]);
const bag = makeReactive(new Set(["a", "b"]));
const map = makeReactive(new Map([["x", 1]]));
const unAll = observe(list, (v, prop) => console.log("list changed", prop));
const unBag = observe(bag, (v, prop) => console.log("set changed", prop));
const unMap = observe(map, (v, prop) => console.log("map changed", prop));
const person = makeReactive({ name: "Ada", age: 36 });
const unName = subscribe([person, "name"], (v) => console.log("name:", v));
person.name = "Grace";
unAll?.(); unBag?.(); unMap?.(); unName?.();const source = makeReactive({ x: 1, y: 2 });
// Read-only derivative
const sum = derivate(source, s => ({ sum: s.x + s.y }));
subscribe(sum, () => console.log("sum:", sum.sum));
// Two-way bind by shape
const target: any = { x: 0, y: 0 };
bindBy(target, source);
source.x = 3; // target.x becomes 3const complex = makeReactive({ d: new Date(), w: new WeakRef({ a: 1 }) });
JSON.stringify(safe(complex));- Subscriptions fire only on actual changes.
observeadaptsSet/Mapto emit iteration changes.- To stop listening, keep the disposer returned by
subscribe/observeand call it.
- core/Assigned
- core/Legacy
- core/Mainline
- core/Primitives
- core/Specific
- core/Subscript
- index
- wrap/AssignObject
- wrap/Symbol
- wrap/Utils
This project is licensed under the MIT License.