/**
 * 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;
    /**
     * 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>;
    /**
     * Update the current value in place.
     *
     * @param fn A function to update the value. If false is returned, observers are not notified.
     *
     * @example
     * ```tsx
     * import { $, watch } from "rvx";
     *
     * const items = $([]);
     *
     * watch(items, items => {
     *   console.log("Items:", items);
     * });
     *
     * items.update(items => {
     *   items.push("foo");
     *   items.push("bar");
     * });
     * ```
     */
    update(fn: (value: T) => void | boolean): void;
    /**
     * 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 it's 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);
/**
 * 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: Expression<T>, effect: (value: T) => void): 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 it's 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;
/**
 * Run a function while not tracking signal accesses.
 *
 * This is the opposite of {@link track}.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 *
 * @example
 * ```tsx
 * import { $, untrack, watch } from "rvx";
 *
 * const a = $(2);
 * const b = $(3);
 *
 * watch(() => a.value + untrack(() => b.value), sum => {
 *   console.log("Sum:", sum);
 * });
 *
 * a.value = 4;
 * b.value = 5;
 * ```
 */
export declare function untrack<T>(fn: () => T): T;
/**
 * Run a function while tracking signal accesses. This is the default behavior.
 *
 * This is the opposite of {@link untrack}.
 *
 * @param fn The function to run.
 * @returns The function's return value.
 */
export declare function track<T>(fn: () => 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>(fn: 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: 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: Expression<I>, mapFn: MapFn<I, O>): Expression<O>;
