2021-06-18 13:05:06 +02:00
|
|
|
import type Ticker from '../Ticker'
|
|
|
|
import type {$IntentionalAny, VoidFn} from '../types'
|
|
|
|
import type Tappable from '../utils/Tappable'
|
|
|
|
|
|
|
|
type IDependent = (msgComingFrom: IDerivation<$IntentionalAny>) => void
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Common interface for derivations.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
export interface IDerivation<V> {
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Whether the object is a derivation.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
isDerivation: true
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the derivation is hot.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
isHot: boolean
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a `Tappable` of the changes of this derivation.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
changes(ticker: Ticker): Tappable<V>
|
|
|
|
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Like {@link changes} but with a different performance model. `changesWithoutValues` returns a {@link Tappable} that
|
|
|
|
* updates every time the derivation is updated, even if the value didn't change, and the callback is called without
|
|
|
|
* the value. The advantage of this is that you have control over when the derivation is freshened, it won't
|
|
|
|
* automatically be kept fresh.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
changesWithoutValues(): Tappable<void>
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Keep the derivation hot, even if there are no tappers (subscribers).
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
keepHot(): VoidFn
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Convenience method that taps (subscribes to) the derivation using `this.changes(ticker).tap(fn)` and immediately calls
|
|
|
|
* the callback with the current value.
|
|
|
|
*
|
2022-02-23 22:53:39 +01:00
|
|
|
* @param ticker - The ticker to use for batching.
|
|
|
|
* @param fn - The callback to call on update.
|
2022-01-19 13:06:13 +01:00
|
|
|
*
|
|
|
|
* @see changes
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
tapImmediate(ticker: Ticker, fn: (cb: V) => void): VoidFn
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a derivation as a dependent of this derivation.
|
|
|
|
*
|
2022-02-23 22:53:39 +01:00
|
|
|
* @param d - The derivation to be made a dependent of this derivation.
|
2022-01-19 13:06:13 +01:00
|
|
|
*
|
|
|
|
* @see removeDependent
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
addDependent(d: IDependent): void
|
2022-01-19 13:06:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a derivation as a dependent of this derivation.
|
|
|
|
*
|
2022-02-23 22:53:39 +01:00
|
|
|
* @param d - The derivation to be removed from as a dependent of this derivation.
|
2022-01-19 13:06:13 +01:00
|
|
|
*
|
|
|
|
* @see addDependent
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
removeDependent(d: IDependent): void
|
|
|
|
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Gets the current value of the derivation. If the value is stale, it causes the derivation to freshen.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
getValue(): V
|
|
|
|
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Creates a new derivation from this derivation using the provided mapping function. The new derivation's value will be
|
|
|
|
* `fn(thisDerivation.getValue())`.
|
|
|
|
*
|
2022-02-23 22:53:39 +01:00
|
|
|
* @param fn - The mapping function to use. Note: it accepts a plain value, not a derivation.
|
2022-01-19 13:06:13 +01:00
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
map<T>(fn: (v: V) => T): IDerivation<T>
|
|
|
|
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Same as {@link IDerivation.map}, but the mapping function can also return a derivation, in which case the derivation returned
|
|
|
|
* by `flatMap` takes the value of that derivation.
|
|
|
|
*
|
|
|
|
* @example
|
2022-02-15 22:59:34 +01:00
|
|
|
* ```ts
|
|
|
|
* // Simply using map() here would return the inner derivation when we call getValue()
|
2022-01-19 13:06:13 +01:00
|
|
|
* new Box(3).derivation.map((value) => new Box(value).derivation).getValue()
|
|
|
|
*
|
2022-02-15 22:59:34 +01:00
|
|
|
* // Using flatMap() eliminates the inner derivation
|
2022-01-19 13:06:13 +01:00
|
|
|
* new Box(3).derivation.flatMap((value) => new Box(value).derivation).getValue()
|
2022-02-15 22:59:34 +01:00
|
|
|
* ```
|
2022-01-19 13:06:13 +01:00
|
|
|
*
|
2022-02-23 22:53:39 +01:00
|
|
|
* @param fn - The mapping function to use. Note: it accepts a plain value, not a derivation.
|
2022-01-19 13:06:13 +01:00
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
flatMap<R>(
|
|
|
|
fn: (v: V) => R,
|
|
|
|
): IDerivation<R extends IDerivation<infer T> ? T : R>
|
|
|
|
}
|
|
|
|
|
2022-01-19 13:06:13 +01:00
|
|
|
/**
|
|
|
|
* Returns whether `d` is a derivation.
|
|
|
|
*/
|
2021-06-18 13:05:06 +02:00
|
|
|
export function isDerivation(d: any): d is IDerivation<unknown> {
|
|
|
|
return d && d.isDerivation && d.isDerivation === true
|
|
|
|
}
|