/**
 * A function that is called to dispose something.
 */
export type TeardownHook = () => void;
/**
 * Run a function while capturing teardown hooks.
 *
 * + If an error is thrown by the specified function, teardown hooks are called in reverse registration order and the error is re-thrown.
 * + If an error is thrown by a teardown hook, remaining ones are not called and the error is re-thrown.
 *
 * @param fn The function to run.
 * @returns A function to run all captured teardown hooks in reverse registration order.
 */
export declare function capture(fn: () => void): TeardownHook;
/**
 * Run a function while capturing teardown hooks.
 *
 * + When disposed before the specified function finishes, teardown hooks are called in reverse registration order immediately after the function finishes.
 * + If an error is thrown by the specified function, teardown hooks are called in reverse registration order and the error is re-thrown.
 * + If an error is thrown by a teardown hook, remaining ones are not called and the error is re-thrown.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 */
export declare function captureSelf<T>(fn: (dispose: TeardownHook) => T): T;
/**
 * Run a function while intentionally leaking teardown hooks.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 */
export declare function leak<T>(fn: () => T): T;
/**
 * Run a function and immediately call teardown hooks if it throws an error.
 *
 * + If an error is thrown, teardown hooks are immediately called in reverse registration order and the error is re-thrown.
 * + If no error is thrown, teardown hooks are registered in the outer context.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 */
export declare function teardownOnError<T>(fn: () => T): T;
/**
 * Register a teardown hook to be called when the current lifecycle is disposed.
 *
 * This has no effect if teardown hooks are not captured in the current context.
 *
 * @param hook The hook to register. This may be called multiple times.
 */
export declare function teardown(hook: TeardownHook): void;
/**
 * Run a function in isolation from the following side effect causing APIs:
 * + Teardown hooks are leaked. To isolate only teardown hooks, use {@link leak} instead.
 * + Signal accesses are not tracked and the default tracking behavior is restored. To only isolate signal accesses, use {@link untrack} instead.
 *
 * Note, that batches and contexts are not isolated.
 *
 * @param fn The function to run.
 * @param args The function arguments.
 * @returns The function's return value.
 */
export declare function isolate<F extends (...args: any) => any>(fn: F, ...args: Parameters<F>): ReturnType<F>;
/**
 * Internal test utility to check if lifecycle & access tracking is isolated in the current context.
 */
export declare function isIsolated(): boolean;
/**
 * Represents the source that a signal has been derived from.
 *
 * When deriving a signal, the source should be passed via the signal constructor or shorthand.
 * This has no impact on how a signal behaves, but allows other APIs to locate metadata about a signal's source.
 *
 * @example
 * ```js
 * function trim(source: Signal<string>) {
 *   const input = $(source.value, source);
 *   ...
 *   return input;
 * }
 * ```
 */
export type SignalSource = Signal<unknown> | undefined;
/**
 * Represents a value that changes over time.
 */
export declare class Signal<T> {
    #private;
    /**
     * The current value without access tracking or observer notifications when set.
     */
    inert: T;
    /**
     * Create a new signal.
     *
     * @param value The initial value.
     * @param source The {@link SignalSource source} this signal has been derived from.
     */
    constructor(value: T, source?: SignalSource);
    /**
     * Reactively access the current value.
     */
    get value(): T;
    /**
     * Set the current value.
     *
     * If the new value is the same as the previous one, no observers are notified.
     *
     * @example
     * ```tsx
     * import { $, watch } from "rvx";
     *
     * const count = $(0);
     *
     * watch(count, count => {
     *   console.log("Count:", count);
     * });
     *
     * count.value++;
     * ```
     */
    set value(value: T);
    /**
     * The {@link SignalSource source}, this signal has been derived from.
     */
    get source(): SignalSource;
    /**
     * The root {@link SignalSource source}, this signal has been derived from or this signal itself if it hasn't been derived.
     */
    get root(): Signal<unknown>;
    /**
     * Check if this signal has any active observers.
     */
    get active(): boolean;
    /**
     * Manually access this signal.
     */
    access(): void;
    /**
     * Manually notify observers.
     *
     * During batches, notifications are deferred.
     */
    notify(): void;
    /**
     * Pass this signal to a function and get its result.
     *
     * @example
     * ```tsx
     * const value = $(42);
     *
     * <TextInput value={
     *   value
     *     .pipe(parseInt)
     *     .pipe(trim)
     * } />
     * ```
     */
    pipe<A extends any[], R>(fn: (self: this, ...args: A) => R, ...args: A): R;
}
/**
 * Create a new signal.
 *
 * @param value The initial value.
 * @param source The {@link SignalSource source} this signal has been derived from.
 * @returns The signal.
 */
export declare function $(): Signal<void>;
export declare function $<T>(value: T, source?: SignalSource): Signal<T>;
/**
 * A value, signal or function to get a value.
 *
 * @example
 * ```tsx
 * import { $, watch } from "rvx";
 *
 * const message = $("Example");
 *
 * // Not reactive:
 * watch(message.value, message => {
 *   console.log("A:", message);
 * });
 *
 * // Reactive:
 * watch(message, message => {
 *   console.log("B:", message);
 * });
 *
 * // Reactive:
 * watch(() => message.value, message => {
 *   console.log("C:", message);
 * });
 *
 * message.value = "Hello World!";
 * ```
 */
export type Expression<T> = T | Signal<T> | (() => T);
/**
 * Utility to get the result type of an expression.
 */
export type ExpressionResult<T> = T extends Expression<infer R> ? R : never;
/**
 * Utility type for expressions that should never be static values.
 *
 * This can be used instead of the {@link Expression} type in places where accepting static values doesn't make sense.
 */
export type Reactive<T> = Signal<T> | (() => T);
/**
 * Utility type to require `T` to not be reactive.
 */
export type Static<T> = unknown extends T ? never : Exclude<T, Reactive<any>>;
/**
 * Watch an expression until the current lifecycle is disposed.
 *
 * + Both the expression and effect are called at least once immediately.
 * + Lifecycle hooks from the expression or effect are called before a signal update is processed or when the current lifecycle is disposed.
 *
 * @param expr The expression to watch.
 * @param effect An optional function to call with each expression result without tracking signal accesses.
 *
 * @example
 * ```tsx
 * import { $, watch } from "rvx";
 *
 * const count = $(0);
 *
 * // Capture teardown hooks registered by "watch":
 * const dispose = capture(() => {
 *   // Start watching:
 *   watch(count, count => {
 *     console.log("Count:", count);
 *   });
 * });
 *
 * count.value = 1;
 *
 * // Stop watching:
 * dispose();
 *
 * count.value = 2;
 * ```
 */
export declare function watch<T>(expr: Reactive<T>, effect: (value: T) => void): void;
/**
 * @deprecated
 * This call can be removed because the expression is always static. You can call the effect directly.
 */
export declare function watch<T>(expr: Static<T>, effect: (value: T) => void): void;
/**
 * Watch an expression until the current lifecycle is disposed.
 *
 * + Both the expression and effect are called at least once immediately.
 * + Lifecycle hooks from the expression or effect are called before a signal update is processed or when the current lifecycle is disposed.
 *
 * @param expr The expression to watch.
 * @param effect An optional function to call with each expression result without tracking signal accesses.
 *
 * @example
 * ```tsx
 * import { $, watch } from "rvx";
 *
 * const count = $(0);
 *
 * // Capture teardown hooks registered by "watch":
 * const dispose = capture(() => {
 *   // Start watching:
 *   watch(count, count => {
 *     console.log("Count:", count);
 *   });
 * });
 *
 * count.value = 1;
 *
 * // Stop watching:
 * dispose();
 *
 * count.value = 2;
 * ```
 */
export declare function watch(expr: () => void): void;
export declare function watch<T>(expr: Expression<T>, effect: (value: T) => void): void;
/**
 * Watch an expression until the current lifecycle is disposed.
 *
 * @param expr The expression to watch.
 * @param effect A function to call with each subsequent expression result without tracking signal accesses.
 * @returns The first expression result.
 */
export declare function watchUpdates<T>(expr: Reactive<T>, effect: (value: T) => void): T;
/**
 * @deprecated
 * This call can be removed because the expression is always static.
 */
export declare function watchUpdates<T>(expr: Static<T>, effect: (value: T) => void): T;
/**
 * Watch an expression until the current lifecycle is disposed.
 *
 * @param expr The expression to watch.
 * @param effect A function to call with each subsequent expression result without tracking signal accesses.
 * @returns The first expression result.
 */
export declare function watchUpdates<T>(expr: Expression<T>, effect: (value: T) => void): T;
/**
 * Wrap an expression to re-run only when any accessed signal has been updated.
 *
 * + Lifecycle hooks in the expression are not supported.
 * + The context from where `lazy` was called is available within the expression.
 *
 * @param expr The expression to wrap.
 */
export declare function lazy<T>(expr: () => T): () => T;
/**
 * Defer signal updates until a function finishes.
 *
 * + When nesting batches, updates are processed after the most outer batch has completed.
 * + When updates cause immediate side effects, these side effects will run as part of the batch.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 *
 * @example
 * The example below outputs `5` and `9` once. Without batching the output would be `5, 7, 9`.
 * ```tsx
 * import { batch, $, watch } from "rvx";
 *
 * const a = $(2);
 * const b = $(3);
 *
 * watch(() => a.value + b.value, value => {
 *   console.log("Sum:", value);
 * });
 *
 * batch(() => {
 *   a.value = 4;
 *   b.value = 5;
 * });
 * ```
 */
export declare function batch<T>(fn: () => T): T;
/**
 * {@link watch Watch} an expression and get a function to reactively access its result.
 *
 * @param expr The expression to watch.
 * @returns A function to reactively access the latest result.
 *
 * @example
 * ```tsx
 * import { $, memo, watch } from "rvx";
 *
 * const count = $(42);
 *
 * const computed = memo(() => someExpensiveComputation(count.value));
 *
 * watch(computed, count => {
 *   console.log("Count:", count);
 * });
 * ```
 */
export declare function memo<T>(expr: Reactive<T>): () => T;
/**
 * @deprecated
 * This call can be removed because the expression is always static. You can use the value directly.
 */
export declare function memo<T>(expr: Static<T>): () => T;
/**
 * {@link watch Watch} an expression and get a function to reactively access its result.
 *
 * @param expr The expression to watch.
 * @returns A function to reactively access the latest result.
 *
 * @example
 * ```tsx
 * import { $, memo, watch } from "rvx";
 *
 * const count = $(42);
 *
 * const computed = memo(() => someExpensiveComputation(count.value));
 *
 * watch(computed, count => {
 *   console.log("Count:", count);
 * });
 * ```
 */
export declare function memo<T>(expr: Expression<T>): () => T;
/**
 * {@link get Evaluate an expression} without tracking signal accesses.
 *
 * @param expr The expression to evaluate.
 * @returns The function's return value.
 *
 * @example
 * ```tsx
 * import { $, untrack, watch } from "rvx";
 *
 * const a = $(2);
 * const b = $(3);
 *
 * watch(() => a.value + untrack(b), sum => {
 *   console.log("Sum:", sum);
 * });
 *
 * // This causes an update:
 * a.value = 4;
 *
 * // This has no effect:
 * b.value = 5;
 * ```
 */
export declare function untrack<T>(expr: Reactive<T>): T;
/**
 * @deprecated
 * This call can be removed because the expression is always static. You can use the value directly.
 */
export declare function untrack<T>(expr: Static<T>): T;
/**
 * {@link get Evaluate an expression} without tracking signal accesses.
 *
 * @param expr The expression to evaluate.
 * @returns The function's return value.
 *
 * @example
 * ```tsx
 * import { $, untrack, watch } from "rvx";
 *
 * const a = $(2);
 * const b = $(3);
 *
 * watch(() => a.value + untrack(b), sum => {
 *   console.log("Sum:", sum);
 * });
 *
 * // This causes an update:
 * a.value = 4;
 *
 * // This has no effect:
 * b.value = 5;
 * ```
 */
export declare function untrack<T>(expr: Expression<T>): T;
/**
 * Check if signal accesses are currently tracked.
 */
export declare function isTracking(): boolean;
/**
 * Run a function while tracking signal accesses to invoke the trigger callback when updated.
 *
 * See {@link trigger}.
 */
export interface TriggerPipe {
    <T>(expr: Reactive<T>): T;
    /**
     * @deprecated
     * This call can be removed because the expression is always static. You can use the value directly.
     */
    <T>(expr: Static<T>): T;
    <T>(expr: Expression<T>): T;
}
/**
 * Create an expression evaluator pipe that calls a function once when any accessed signals from the latest evaluated expression are updated.
 *
 * + When the lifecycle at which the pipe was created is disposed, the callback function will not be called anymore.
 * + It is guaranteed that the function is called before any other observers like {@link watch} or {@link effect} are notified.
 * + If pipes are nested, the callback for the most inner one is called first.
 *
 * @param callback The callback to invoke when a signal is updated.
 * @returns The pipe to evaluate expressions.
 */
export declare function trigger(callback: () => void): TriggerPipe;
/**
 * Manually evaluate an expression in the current context.
 *
 * This can be used to access reactive and non reactive inputs.
 *
 * @param expr The expression to evaluate.
 * @returns The expression result.
 *
 * @example
 * ```tsx
 * import { $, get } from "rvx";
 *
 * const count = $(42);
 *
 * get(42) // 42
 * get(count) // 42
 * get(() => 42) // 42
 * ```
 */
export declare function get<T>(expr: Reactive<T>): T;
/**
 * @deprecated
 * This call can be removed because the expression is always static. You can use the value directly.
 */
export declare function get<T>(expr: Static<T>): T;
/**
 * Manually evaluate an expression in the current context.
 *
 * This can be used to access reactive and non reactive inputs.
 *
 * @param expr The expression to evaluate.
 * @returns The expression result.
 *
 * @example
 * ```tsx
 * import { $, get } from "rvx";
 *
 * const count = $(42);
 *
 * get(42) // 42
 * get(count) // 42
 * get(() => 42) // 42
 * ```
 */
export declare function get<T>(expr: Expression<T>): T;
export type MapFn<I, O> = (input: I) => O;
/**
 * Map an expression value while preserving if the expression is static or not.
 *
 * @example
 * ```tsx
 * import { $, map, get } from "rvx";
 *
 * const count = $(42);
 * const doubleCount = map(count, value => value * 2);
 *
 * get(doubleCount) // 84
 * ```
 */
export declare function map<I, O>(input: Reactive<I>, mapFn: MapFn<I, O>): Expression<O>;
/**
 * @deprecated
 * This call can be removed because the input is always static. You can call the map function directly.
 */
export declare function map<I, O>(input: Static<I>, mapFn: MapFn<I, O>): Expression<O>;
/**
 * Map an expression value while preserving if the expression is static or not.
 *
 * @example
 * ```tsx
 * import { $, map, get } from "rvx";
 *
 * const count = $(42);
 * const doubleCount = map(count, value => value * 2);
 *
 * get(doubleCount) // 84
 * ```
 */
export declare function map<I, O>(input: Expression<I>, mapFn: MapFn<I, O>): Expression<O>;
//# sourceMappingURL=signals.d.ts.map