value-enhancer
Version:
Enhance value with plain and explicit reactive wrapper. Think of it as hook-style signals.
167 lines (154 loc) • 5.86 kB
text/typescript
/**
* A ReadonlyVal contains a readonly `value` and does not have a `set` method.
*/
export interface ReadonlyVal<TValue = any> {
/** Display debug name. */
readonly name?: string;
/**
* Current value of the val.
*/
readonly value: TValue;
/**
* A version representation of the value.
* If two versions of a val is not equal(`Object.is`), it means the `value` has changed (event if the `value` is equal).
*/
readonly $version: ValVersion;
/**
* Get current value of the val.
*/
get: () => TValue;
/**
* Create a new ReadonlyVal referencing the value of the current ReadonlyVal as source.
* (It is just like `derive` a val without `transform`. It is simpler hence more efficient.)
* All ref ReadonlyVals share the same value from the source ReadonlyVal.
*
* With this pattern you can pass a ref ReadonlyVal to downstream.
* The ref ReadonlyVals can be safely disposed without affecting the source ReadonlyVal and other ref ReadonlyVals.
*/
ref(): ReadonlyVal<TValue>;
/**
* Subscribe to value changes without immediate emission.
* @param subscriber
* @param eager by default subscribers will be notified on next tick. set `true` to notify subscribers of value changes synchronously.
* @returns a disposer function that cancels the subscription
*/
reaction(subscriber: ValSubscriber<TValue>, eager?: boolean): ValDisposer;
/**
* Subscribe to value changes with immediate emission.
* @param subscriber
* @param eager by default subscribers will be notified on next tick. set `true` to notify subscribers of value changes synchronously.
* @returns a disposer function that cancels the subscription
*/
subscribe(subscriber: ValSubscriber<TValue>, eager?: boolean): ValDisposer;
/**
* Subscribe to value changes without immediate emission.
* The subscribers will be called before sync and async subscribers from [[reaction]] and [[subscribe]].
* It is mainly used for chaining Vals.
* @param subscriber
* @returns a disposer function that cancels the subscription
*/
$valCompute(subscriber: ValSubscriber<void>): ValDisposer;
/**
* Remove the given subscriber.
* Remove all if no subscriber provided.
* @param subscriber
*/
unsubscribe(subscriber?: (...args: any[]) => any): void;
/**
* Remove all subscribers.
*/
dispose(): void;
}
/**
* A Val contains a writable `value` property and a `set` method.
*/
export interface Val<TValue = any> extends ReadonlyVal<TValue> {
/** Current value of the val */
value: TValue;
/** Set new value */
set: (value: TValue) => void;
/**
* Create a new ReadonlyVal referencing the value of the current ReadonlyVal as source.
* (It is just like `derive` a val without `transform`. It is simpler hence more efficient.)
* All ref ReadonlyVals share the same value from the source ReadonlyVal.
*
* With this pattern you can pass a ref ReadonlyVal to downstream.
* The ref ReadonlyVals can be safely disposed without affecting the source ReadonlyVal and other ref ReadonlyVals.
*/
ref(): ReadonlyVal<TValue>;
/**
* Create a new ReadonlyVal referencing the value of the current ReadonlyVal as source.
* (It is just like `derive` a val without `transform`. It is simpler hence more efficient.)
* All ref ReadonlyVals share the same value from the source ReadonlyVal.
*
* With this pattern you can pass a ref ReadonlyVal to downstream.
* The ref ReadonlyVals can be safely disposed without affecting the source ReadonlyVal and other ref ReadonlyVals.
*/
ref(writable?: false): ReadonlyVal<TValue>;
/**
* Create a new Val referencing the value of the current Val as source.
* All ref Vals share the same value from the source Val.
* The act of setting a value on the ref Val is essentially setting the value on the source Val.
*
* With this pattern you can pass a ref Val as a writable Val to downstream.
* The ref Vals can be safely disposed without affecting the source Val and other ref Vals.
*/
ref(writable: true): Val<TValue>;
/**
* @param writable If true, creates a new Ref Val referencing the value of the current Val as source.
* If false, creates a new Ref ReadonlyVal referencing the value of the current Val as source.
*/
ref(writable?: boolean): ReadonlyVal<TValue> | Val<TValue>;
}
export type ValSetValue<TValue = any> = (value: TValue) => void;
export type ValEqual<TValue = any> = (
newValue: TValue,
oldValue: TValue
) => boolean;
export type ValSubscriber<TValue = any> = (newValue: TValue) => void;
export type ValDisposer = () => void;
/**
* Custom config for the val.
*/
export interface ValConfig<TValue = any> {
/** Debug name. */
readonly name?: string;
/**
* Compare two values. Default `Object.is`.
* `false` to disable equality check.
*/
readonly equal?: ValEqual<TValue> | false;
/**
* Set the default behavior of subscription and reaction.
* Emission triggers synchronously if `true`. Default `false`.
*/
readonly eager?: boolean;
/**
* A callback invoked with the old value when a new value is set.
* @param oldValue The old value being replaced.
*/
readonly onDisposeValue?: (oldValue: TValue) => void;
}
export type ValVersion = any;
export type UnwrapVal<T> = T extends ReadonlyVal<infer TValue> ? TValue : T;
export type FlattenVal<T> = ReadonlyVal<UnwrapVal<UnwrapVal<T>>>;
/**
* @internal
* @ignore
*/
export type ValInputsValueTuple<TValInputs extends readonly ReadonlyVal[]> =
Readonly<{
[K in keyof TValInputs]: ExtractValValue<TValInputs[K]>;
}>;
/**
* @internal
* @ignore
*/
export type ExtractValValue<TVal> = TVal extends ReadonlyVal<infer TValue>
? TValue
: never;
/**
* @internal
* @ignore
*/
export type NoInfer<T> = [T][T extends any ? 0 : never];