import { Signal } from 'signal-polyfill';

declare interface Action<Params extends Array<unknown>, ReturnValue> {
    (...args: Params): ReturnValue;
}

/**
 * Transactionally apply a set of changes. Actions should happen in response
 * to IO events. They cannot be nested.
 */
export declare const action: <Params extends Array<unknown>, ReturnValue>(handler: (...args: Params) => ReturnValue) => Action<Params, ReturnValue>;

export declare interface Atom<Value> {
    /**
     * Staged value used during transactions.
     * @private
     */
    _s: Signal.State<Value>;
    /**
     * Committed value.
     * @private
     */
    _c: Signal.State<Value>;
}

/**
 * Store a single value. Values can be read or replaced. Use `swap` to replace
 * the value inside an action.
 *
 * Reading state in a computed or effect will subscribe to changes.
 */
export declare const atom: <Value>(initialState: Value) => Atom<Value>;

export declare interface Computed<Value> {
    /**
     * Staged value used during transactions.
     */
    _s: Signal.Computed<Value>;
    /**
     * Committed value.
     */
    _c: Signal.Computed<Value>;
}

/**
 * Compute and cache a value. Derivers are cached by the atoms they use. If
 * the atoms change, the deriver will recompute the value the next time it is
 * called.
 */
export declare const computed: <Value>(deriver: () => Value) => Computed<Value>;

/**
 * Get the value of an atom or computed.
 */
export declare const get: <Value>(store: Atom<Value> | Computed<Value>) => Value;

export { Signal }

/**
 * Replace the current state of an atom. Can only be executed inside
 * a transaction. If the transaction fails, the value is reverted.
 */
export declare const swap: <Value>(atom: Atom<Value>, newState: Value) => void;

export { }
