import { Disposable, $O, Observable, Auto, Change, Observer, ObservedSlot, ObserverTarget } from './ed456245';

/**
 * An observable getter that memoizes its result.
 *
 * The memoization is observed, so when a dependency changes,
 * the memoized value is released and observers are notified.
 */
interface Derived<T = any> extends Disposable {
    /** The underlying observable */
    [$O]?: Observable;
    /** The underlying observer */
    auto: Auto;
    /** Get the current value */
    (): T;
}
declare function isDerived(value: unknown): value is Derived;
/** Convert all `Derived<T>` property types into `T` */
declare type WithDerived<T extends object> = {
    [P in keyof T]: T[P] extends Derived<infer U> ? U : T[P];
};

/**
 * Pass an **object** to receive an observable proxy.
 * Pass a **function** to receive an observable getter.
 * Anything else is returned as-is.
 */
declare function o<T>(value: T): T extends () => infer U ? Derived<U> : T extends Function ? Derived : T;

/**
 * Create a promise to resolve when the given condition returns true.
 * Any observable access in the condition is tracked.
 */
declare const when: (condition: () => boolean) => Promise<void>;

declare type WatchedState = ObserverTarget & {
    forEach?: (cb: (value: any, key: any, ctx: any) => void) => void;
};
declare type ChangeHandler = (change: Change) => void;
/**
 * Watch a single property.
 * If its value is observable, watch it recursively.
 */
declare function watch<P>(root: Map<P, any>, key: P, onChange: (change: Change) => void): Watcher;
declare function watch<T extends object, P extends string & keyof T>(root: T, key: P, onChange: (change: Change) => void): Watcher;
/**
 * Watch an observable tree for changes.
 * Only observable objects are searched for watchable values.
 */
declare function watch(root: object, onChange: ChangeHandler): Watcher;
/** An observer of deep changes */
declare class Watcher extends Observer {
    readonly root: object;
    readonly key?: any;
    observed: Set<ObservedSlot>;
    counts: Map<object, number>;
    constructor(root: object, onChange: ChangeHandler, key?: any);
    watch: (value: any, key?: any, ctx?: any) => void;
    unwatch: (value: any, key?: any, ctx?: any) => void;
    dispose(): void;
    protected _watch(target: WatchedState): void;
    protected _unwatch(target: WatchedState): void;
}

/**
 * Get the original object from an observable proxy,
 * or wrap a function to disable observation inside it.
 *
 * Read `no` as "non-observable", essentially the reverse of the `o` function.
 */
declare function no<T>(value: T): T;

/** Run an effect without any observable tracking */
declare function noto<T>(effect: () => T): T;

export { Derived, Watcher, WithDerived, isDerived, no, noto, o, watch, when };
