wana
Version:
Easy observable state for React
125 lines (120 loc) • 4.41 kB
TypeScript
interface Disposable {
/** Release any memory that would otherwise leak */
dispose: () => void;
}
declare type Falsy = false | null | undefined;
/** For accessing the proxied state */
declare const $$: unique symbol;
/** For storing observers and the observable proxy */
declare const $O: unique symbol;
/** For injecting custom proxy traps */
declare const $T: unique symbol;
/** Watch the properties of the given observable object */
declare const shallowChanges: (target: ObserverTarget, onChange: (change: Change) => void) => ChangeObserver;
/** A function that can subscribe to observable objects. */
declare abstract class Observer implements Disposable {
observed: ReadonlySet<ObservedSlot>;
onChange: ((change: Change) => void) | null;
/** The current nonce of our observed values combined */
get nonce(): number;
dispose(): void;
}
/** @internal */
declare class Observable<T extends object = any> extends Map<ObservedKey, ObservedSlot> {
readonly source?: T | undefined;
readonly proxy: T | undefined;
constructor(source?: T | undefined);
/** Return true if at least one observer exists for the given key. */
has(key: ObservedKey): boolean;
/** Return a `Set` of observers for the given key, even if not observed. */
get(key: ObservedKey): ObservedSlot;
/** Create an observer for the given key. */
observe(key: ObservedKey, onChange: (change: Change) => void): ChangeObserver;
}
/** Mutable state with an associated observable */
declare type ObserverTarget = object & {
[$O]?: Observable;
};
/** Any value acting as an object key */
declare type ObservedKey = any;
/** An observer set with metadata about what's being observed */
declare class ObservedSlot extends Set<ChangeObserver> {
readonly owner: Observable;
readonly key: ObservedKey;
nonce: number;
constructor(owner: Observable, key: ObservedKey);
onChange(change: Change): void;
}
/** An observed mutation of an observable object. */
interface Change<T = any> {
op: 'add' | 'replace' | 'remove' | 'splice' | 'clear' | 'define';
target: object;
key?: any;
value?: T;
oldValue?: T;
}
/** The most basic observer of changes. */
interface ChangeObserver extends Disposable {
onChange: ((change: Change) => void) | null;
}
/** Run an effect when its tracked values change. */
declare function auto(effect: () => void, config?: AutoConfig): Auto;
interface AutoConfig {
/** When true, react to changes immediately. By default, changes are delayed until the next microtask loop */
sync?: boolean;
/** By default, rerun the last effect (after any delay) */
onDirty?: Auto['onDirty'];
/** By default, errors are rethrown */
onError?: Auto['onError'];
/** Run an effect after an `observer` is activated */
onCommit?: Auto['onCommit'];
/** Run an effect after being disposed */
onDispose?: Auto['onDispose'];
}
declare class Auto {
sync: boolean;
dirty: boolean;
nonce: number;
observer: AutoObserver | null;
onDirty: (this: Auto) => void;
onError: (this: Auto, error: Error) => void;
onCommit: (observer: AutoObserver) => void;
onDispose: () => void;
constructor(config?: AutoConfig);
run<T extends Function>(compute: T): any;
/** Rerun the last effect and commit its observer */
rerun(): any;
/**
* Replace the current `observer`.
*
* Pass a nonce to bail out if observed values have since changed.
*/
commit(observer: AutoObserver, nonce?: number): boolean;
dispose(): void;
/**
* @internal
* Create an observer and start observing.
*
* The given `effect` is used by `rerun` calls made after
* the new observer is committed.
*/
start(effect: Function): AutoObserver;
/**
* @internal
* Stop observing and reset the `dirty` flag.
*/
stop(): this;
/**
* @internal
* Replace the current `observer` when appropriate.
*/
clear(): void;
protected _onChange(change: Change): void;
protected _onDirty(): void;
}
declare class AutoObserver extends Observer {
readonly effect: Function;
observed: Set<ObservedSlot>;
constructor(effect: Function);
}
export { $$, $O, $T, Auto, AutoConfig, AutoObserver, Change, ChangeObserver, Disposable, Falsy, Observable, ObservedSlot, Observer, ObserverTarget, auto, shallowChanges };