diff --git a/node_modules/effector/index.d.ts b/node_modules/effector/index.d.ts new file mode 100644 index 000000000..e60c30360 --- /dev/null +++ b/node_modules/effector/index.d.ts @@ -0,0 +1,3133 @@ +/** + * This tuple type is intended for use as a generic constraint to infer concrete + * tuple type of ANY length. + * + * @see https://github.com/krzkaczor/ts-essentials/blob/a4c2485bc3f37843267820ec552aa662251767bc/lib/types.ts#L169 + */ +type Tuple = [T?, ...T[]] +type RoTuple = readonly [T?, ...T[]] + +/** + * Non inferential type parameter usage. NoInfer in source and in return of fn helps with + detecting loose objects against target type. + * + * @see https://github.com/microsoft/TypeScript/issues/14829#issuecomment-504042546 + */ +type NoInfer = [T][T extends any ? 0 : never] + +/** + * Generic Json type + */ + type Json = + | null + | undefined + | boolean + | string + | number + | Json[] + | {[k: string]: Json} + +// Type for extention purpose. Represents combinable sample source. +export type Combinable = {[key: string]: Store} | Tuple> +// Helper type, which unwraps combinable sample source value. +export type GetCombinedValue = Show<{ + [K in keyof T]: T[K] extends Store ? U : never +}> + +export type StoreValue = T extends Store ? S : never +export type EventPayload = T extends Event ? P : never +export type UnitValue = T extends Unit ? V : never +export type EffectParams> = FX extends Effect< + infer P, + any, + any +> + ? P + : never +export type EffectResult> = FX extends Effect< + any, + infer D, + any +> + ? D + : never +export type EffectError> = FX extends Effect< + any, + any, + infer E +> + ? E + : never +type AsyncResult = Done extends Promise ? Async : Done +type OptionalParams = + Args['length'] extends 0 // does handler accept 0 arguments? + ? void // works since TS v3.3.3 + : 0 | 1 extends Args['length'] // is the first argument optional? + /** + * Applying `infer` to a variadic arguments here we'll get `Args` of + * shape `[T]` or `[T?]`, where T(?) is a type of handler `params`. + * In case T is optional we get `T | undefined` back from `Args[0]`. + * We lose information about argument's optionality, but we can make it + * optional again by appending `void` type, so the result type will be + * `T | undefined | void`. + * + * The disadvantage of this method is that we can't restore optonality + * in case of `params?: any` because in a union `any` type absorbs any + * other type (`any | undefined | void` becomes just `any`). And we + * have similar situation also with the `unknown` type. + */ + ? Args[0] | void + : Args[0] +type EffectByHandler = FN extends (...args: infer Args) => infer Done + ? Effect, AsyncResult, Fail> + : never + +export const version: string + +export type kind = 'store' | 'event' | 'effect' | 'domain' | 'scope' + +export type Observer = { + readonly next?: (value: A) => void + //error(err: Error): void + //complete(): void +} + +export type Observable = { + subscribe: (observer: Observer) => Subscription +} + +export type Subscription = { + (): void + unsubscribe(): void +} + +export interface Unit { + readonly kind: kind + readonly __: T +} + +export type UnitTargetable = Unit + +export type CompositeName = { + shortName: string + fullName: string + path: Array +} + +/** + * This is a workaround for https://github.com/microsoft/TypeScript/issues/35162 + * + * The problem was that we couldn't use guard as sample's clock parameter because + * sample's clock-related generic inferred as `unknown` in cases when guard returned + * `Event`. This happens because `Event` has a callable signature. With `Unit` + * as the return type we won't see any problems. + */ +type EventAsReturnType = any extends Payload ? Event : never + +/** + * Function you can subscribe to. + * It can be an intention to change the store, indication of something happening in the application, a command to be executed, aggregated analytics trigger and so on + */ +export interface Event extends Unit { + (payload: Payload): Payload + (this: IfUnknown, payload?: Payload): void + watch(watcher: (payload: Payload) => any): Subscription + map(fn: (payload: Payload) => T): EventAsReturnType + filter(config: { + fn(payload: Payload): payload is T + }): EventAsReturnType + filter(config: {fn(payload: Payload): boolean}): EventAsReturnType + filterMap(fn: (payload: Payload) => T | undefined): EventAsReturnType + prepend(fn: (_: Before) => Payload): Event + subscribe(observer: Observer): Subscription + /** + * @deprecated use js pipe instead + */ + thru(fn: (event: Event) => U): U + getType(): string + compositeName: CompositeName + sid: string | null + shortName: string +} + +export type EventCallable = Event + +/** + * Container for (possibly async) side effects + */ +export interface Effect extends Unit { + (params: Params): Promise + readonly done: Event<{params: Params; result: Done}> + readonly doneData: Event + readonly fail: Event<{params: Params; error: Fail}> + readonly failData: Event + readonly finally: Event< + | { + status: 'done' + params: Params + result: Done + } + | { + status: 'fail' + params: Params + error: Fail + } + > + readonly use: { + (handler: (params: Params) => Promise | Done): Effect< + Params, + Done, + Fail + > + getCurrent(): (params: Params) => Promise + } + pending: Store + inFlight: Store + watch(watcher: (payload: Params) => any): Subscription + filter(config: { + fn(payload: Params): payload is T + }): EventAsReturnType + filter(config: {fn(payload: Params): boolean}): EventAsReturnType + filterMap(fn: (payload: Params) => T | undefined): EventAsReturnType + map(fn: (params: Params) => T): EventAsReturnType + prepend(fn: (_: Before) => Params): Event + subscribe(observer: Observer): Subscription + getType(): string + compositeName: CompositeName + sid: string | null + shortName: string +} +type InferValueFromTupleOfUnits>> = + T[number] extends Unit ? R : never + +export interface Store extends Unit { + reset(...triggers: Array>): this + reset(triggers: Array>): this + getState(): State + map(fn: (state: State, lastState?: T) => T): Store + /** + * @deprecated second argument of `fn` and `firstState` are deprecated, use `updateFilter` or explicit `createStore` instead + */ + map(fn: (state: State, lastState: T) => T, firstState: T): Store + on( + trigger: Unit, + reducer: (state: State, payload: E) => State | void, + ): this + on( + triggers: Unit[], + reducer: (state: State, payload: E) => State | void, + ): this + on>>( + triggers: E, + reducer: (state: State, payload: InferValueFromTupleOfUnits) => State | void, + ): this + off(trigger: Unit): this + subscribe(listener: Observer | ((state: State) => any)): Subscription + updates: Event + watch(watcher: (state: State, payload: undefined) => any): Subscription + watch( + trigger: Unit, + watcher: (state: State, payload: E) => any, + ): Subscription + /** + * @deprecated use js pipe instead + */ + thru(fn: (store: Store) => U): U + defaultState: State + compositeName: CompositeName + shortName: string + sid: string | null + reinit?: Event +} + +export type StoreWritable = Store + +export const is: { + unit(obj: unknown): obj is Unit + store(obj: unknown): obj is Store + event(obj: unknown): obj is Event + effect(obj: unknown): obj is Effect + domain(obj: unknown): obj is Domain + scope(obj: unknown): obj is Scope + attached(obj: unknown): obj is Effect +} + +interface InternalStore extends Store { + setState(state: State): void +} + +/** + * A way to group and process events, stores and effects. Useful for logging and assigning a reset trigger to many effects. + * Domain is notified via onCreateEvent, onCreateStore, onCreateEffect, onCreateDomain methods when events, stores, effects, or nested domains are created + */ +export class Domain implements Unit { + readonly kind: kind + readonly __: any + onCreateEvent(hook: (newEvent: Event) => any): Subscription + onCreateEffect( + hook: (newEffect: Effect) => any, + ): Subscription + onCreateStore( + hook: (newStore: InternalStore) => any, + ): Subscription + onCreateDomain(hook: (newDomain: Domain) => any): Subscription + event(name?: string): Event + event(config: {name?: string; sid?: string}): Event + createEvent(name?: string): Event + createEvent(config: { + name?: string + sid?: string + }): Event + effect(handler: FN): EffectByHandler + effect( + handler: (params: Params) => Done | Promise, + ): Effect + effect(handler: FN): EffectByHandler + effect( + name?: string, + config?: { + handler?: (params: Params) => Promise | Done + sid?: string + }, + ): Effect + effect(config: { + handler?: (params: Params) => Promise | Done + sid?: string + name?: string + }): Effect + createEffect(handler: FN): EffectByHandler + createEffect( + handler: (params: Params) => Done | Promise, + ): Effect + createEffect(handler: FN): EffectByHandler + createEffect(config: { + name?: string + handler: FN + sid?: string + }): EffectByHandler + createEffect( + name?: string, + config?: { + handler?: (params: Params) => Promise | Done + sid?: string + }, + ): Effect + createEffect(config: { + handler?: (params: Params) => Promise | Done + sid?: string + name?: string + }): Effect + domain(name?: string): Domain + createDomain(name?: string): Domain + store( + defaultState: State, + config?: { + name?: string + sid?: string + updateFilter?: (update: State, current: State) => boolean + serialize?: + | 'ignore' + | { + write: (state: State) => SerializedState + read: (json: SerializedState) => State + } + }, + ): Store + createStore( + defaultState: State, + config?: { + name?: string + sid?: string + updateFilter?: (update: State, current: State) => boolean + serialize?: + | 'ignore' + | { + write: (state: State) => SerializedState + read: (json: SerializedState) => State + } + }, + ): Store + sid: string | null + compositeName: CompositeName + shortName: string + getType(): string + history: { + domains: Set + stores: Set> + effects: Set> + events: Set> + } +} + +export type ID = string +export type StateRefOp = + | {type: 'map'; from?: StateRef; fn?: (value: any) => any} + | {type: 'field'; from: StateRef; field: string} + | {type: 'closure'; of: StateRef} +export type StateRef = { + id: ID + current: any + type?: 'list' | 'shape' + before?: StateRefOp[] + noInit?: boolean + sid?: string +} + +export type Stack = { + value: any + a: any + b: any + parent?: Stack + node: Node + page?: any + scope?: Scope + meta?: Record +} + +type BarrierPriorityTag = 'barrier' | 'sampler' | 'effect' + +type FromValue = { + from: 'value' + store: any +} +type FromStore = { + from: 'store' + store: StateRef +} +type FromRegister = { + from: 'a' | 'b' | 'stack' +} + +type ToRegister = { + to: 'a' | 'b' | 'stack' +} +type ToStore = { + to: 'store' + target: StateRef +} + +type MoveCmd = { + id: ID + type: 'mov' + data: Data + order?: { + priority: BarrierPriorityTag + barrierID?: number + } +} + +export type Cmd = + | Compute + | Mov + +type MovValReg = MoveCmd +type MovValStore = MoveCmd +type MovStoreReg = MoveCmd +type MovStoreStore = MoveCmd +type MovRegReg = MoveCmd +type MovRegStore = MoveCmd + +export type Mov = + | MovValReg + | MovValStore + | MovStoreReg + | MovStoreStore + | MovRegReg + | MovRegStore + +export type Compute = { + id: ID + type: 'compute' + data: { + fn?: (data: any, scope: {[key: string]: any}, reg: Stack) => any + safe: boolean + filter: boolean + pure: boolean + } + order?: { + priority: BarrierPriorityTag + barrierID?: number + } +} +export type Node = { + id: ID + next: Array + seq: Array + scope: {[field: string]: any} + meta: {[field: string]: any} + family: { + type: 'regular' | 'crosslink' | 'domain' + links: Node[] + owners: Node[] + } +} + +export const step: { + compute(data: { + fn?: (data: any, scope: {[key: string]: any}, stack: Stack) => any + batch?: boolean + priority?: BarrierPriorityTag | false + safe?: boolean + filter?: boolean + pure?: boolean + }): Compute + filter(data: { + fn: (data: any, scope: {[field: string]: any}, stack: Stack) => boolean + pure?: boolean + }): Compute + run(data: {fn: (data: any, scope: {[field: string]: any}, stack: Stack) => any}): Compute + mov(data: { + from?: 'value' | 'store' | 'stack' | 'a' | 'b' + to?: 'stack' | 'a' | 'b' | 'store' + store?: StateRef + target?: StateRef + batch?: boolean + priority?: BarrierPriorityTag | false + }): Mov +} + +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + /** + * By default TS picks "best common type" `T` between `from` and `to` arguments. + * This lets us forward from `string | number` to `string` for instance, and + * this is wrong. + * + * Fortunately we have a way to disable such behavior. By adding `& {}` to some + * generic type we tell TS "do not try to infer this generic type from + * corresponding argument type". + * + * Generic `T` won't be inferred from `from` any more. Forwarding from "less + * strict" to "more strict" will produce an error as expected. + * + * @see https://www.typescriptlang.org/docs/handbook/type-inference.html#best-common-type + */ + from: Unit + to: Unit | ReadonlyArray> +}): Subscription +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + from: Unit + to: ReadonlyArray> +}): Subscription +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + from: ReadonlyArray> + to: ReadonlyArray> +}): Subscription +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + from: ReadonlyArray> + to: Unit +}): Subscription +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + from: ReadonlyArray> + to: Unit | ReadonlyArray> +}): Subscription +// Allow `* -> void` forwarding (e.g. `string -> void`). +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: {from: Unit; to: Unit}): Subscription +// Do not remove the signature below to avoid breaking change! +/** + * Method to create connection between units in a declarative way. Sends updates from one set of units to another + */ +export function forward(opts: { + from: Unit + to: Unit | ReadonlyArray> +}): Subscription + +/** + * Merges array of units (events, effects or stores), returns a new event, which fires upon trigger of any of given units + * @param units array of units to be merged + */ +export function merge(units: ReadonlyArray>): EventAsReturnType +/** + * Merges array of units (events, effects or stores), returns a new event, which fires upon trigger of any of given units + * @param units array of units to be merged + */ +export function merge>>( + units: T, +): T[number] extends Unit ? Event : never +/** + * Method for destroying units and graph nodes. Low level tool, usually absent in common applications + * @param unit unit to be erased + * @param opts optional configuration object + */ +export function clearNode(unit: Unit | Node, opts?: {deep?: boolean}): void +/** + * Method to create a new graph node. Low level tool, usually absent in common applications + */ +export function createNode(opts?: { + node?: Array + parent?: Array | Node> + child?: Array | Node> + scope?: {[field: string]: any} + meta?: {[field: string]: any} + family?: { + type?: 'regular' | 'crosslink' | 'domain' + owners?: Unit | Node | Array | Node> + links?: Unit | Node | Array | Node> + } + regional?: boolean +}): Node +/** + * Allows to directly start computation from given unit or graph node. Low level tool, usually absent in common applications + * @param unit unit or graph node to launch + * @param payload data to pass to computation + */ +export function launch(unit: Unit | Node, payload: T): void +/** + * Allows to directly start computation from given unit or graph node. Low level tool, usually absent in common applications + * @param config configuration object + */ +export function launch(config: { + target: Unit | Node + params: T + defer?: boolean + page?: any + scope?: Scope + meta?: Record +}): void +/** + * Allows to directly start computation from given unit or graph node. Low level tool, usually absent in common applications + * @param config configuration object + */ +export function launch(config: { + target: Array | Node> + params: any[] + defer?: boolean + page?: any + scope?: Scope + meta?: Record +}): void + +/** + * Method to create an event subscribed to given observable + * @param observable object with `subscribe` method, e.g. rxjs stream or redux store + */ +export function fromObservable(observable: unknown): Event +/** + * Creates an event + */ +export function createEvent(eventName?: string): Event +/** + * Creates an event + */ +export function createEvent(config: { + name?: string + sid?: string + domain?: Domain +}): Event + +/** + * Creates an effect + * @param handler function to handle effect calls + */ +export function createEffect(handler: FN): EffectByHandler +/** + * Creates an effect + * @param handler function to handle effect calls + */ +export function createEffect( + handler: (params: Params) => Done | Promise, +): Effect +/** + * Creates an effect + * @param handler function to handle effect calls + */ +export function createEffect(handler: FN): EffectByHandler +/** + * Creates an effect + */ +export function createEffect(name: string, config: { + handler: FN + sid?: string + domain?: Domain +}): EffectByHandler +/** + * Creates an effect + */ +export function createEffect( + effectName?: string, + config?: { + handler?: (params: Params) => Promise | Done + sid?: string + domain?: Domain + }, +): Effect +/** + * Creates an effect + */ +export function createEffect(config: { + name?: string + handler: FN + sid?: string + domain?: Domain +}): EffectByHandler +/** + * Creates an effect + */ +export function createEffect(config: { + name?: string + handler?: (params: Params) => Promise | Done + sid?: string + domain?: Domain +}): Effect + +/** + * Creates a store + * @param defaultState default state + * @param config optional configuration object + */ +export function createStore( + defaultState: State, + config?: { + name?: string; + sid?: string + updateFilter?: (update: State, current: State) => boolean + serialize?: + | 'ignore' + | { + write: (state: State) => SerializedState + read: (json: SerializedState) => State + } + domain?: Domain; + }, +): Store +export function setStoreName(store: Store, name: string): void + +/** + * @deprecated use combine() instead + */ +export function createStoreObject( + defaultState: State, +): Store<{[K in keyof State]: State[K] extends Store ? U : State[K]}> + +/** + * Chooses one of the cases by given conditions. It "splits" source unit into several events, which fires when payload matches their conditions. + * Works like pattern matching for payload values and external stores + * @param source unit which will trigger computation in split + * @param match object with matching functions which allows to trigger one of created events + */ +export function split< + S, + Match extends {[name: string]: (payload: S) => boolean} +>( + source: Unit, + match: Match, +): Show<{ + [K in keyof Match]: Match[K] extends (p: any) => p is infer R + ? Event + : Event +} & {__: Event}> + +type SplitType< + Cases extends CaseRecord, + Match, + Config, + Source extends Unit, +> = + UnitValue extends CaseTypeReader + ? + Match extends Unit + ? Exclude extends UnitValue + ? Config + : { + error: 'match unit should contain case names' + need: Exclude + got: UnitValue + } + + : Match extends (p: UnitValue) => void + ? Exclude extends ReturnType + ? Config + : { + error: 'match function should return case names' + need: Exclude + got: ReturnType + } + + : Match extends Record) => boolean) | Store> + ? Exclude extends keyof Match + ? MatcherInferenceValidator extends Match + ? Config + : { + error: 'case should extends type inferred by matcher function' + incorrectCases: Show> + } + : { + error: 'match object should contain case names' + need: Exclude + got: keyof Match + } + + : {error: 'not implemented'} + + : { + error: 'source type should extends cases' + sourceType: UnitValue + caseType: CaseTypeReader + } + +/** + * Chooses one of cases by given conditions. It "splits" source unit into several targets, which fires when payload matches their conditions. + * Works like pattern matching for payload values and external units + */ +export function split< + Cases, + Source, + Match extends ( + | Unit + | ((p: UnitValue) => void) + | Record) => boolean) | Store> + ), + Clock, +>( + config: + {source: Source; match: Match; cases: Cases; clock: Clock} extends infer Config + ? + Config extends {cases: CaseRecord; match: any; source: Unit; clock: Unit | Array>} + ? Source extends Unit + ? Cases extends CaseRecord + ? Clock extends Unit | Array> + ? SplitType + : {error: 'clock should be a unit or array of units'; got: Clock} + : {error: 'cases should be an object with units or arrays of units'; got: Cases} + : {error: 'source should be a unit'; got: Source} + + : Config extends {cases: CaseRecord; match: any; source: Unit} + ? Source extends Unit + ? Cases extends CaseRecord + ? SplitType + : {error: 'cases should be an object with units or arrays of units'; got: Cases} + : {error: 'source should be a unit'; got: Source} + + : {error: 'config should be object with fields "source", "match" and "cases"'; got: Config} + + : {error: 'cannot infer config object'} +): void + +type CaseRecord = Record | Array>> + +type MatcherInferenceIncorrectCases = { + [K in Exclude>]: { + caseType: CaseValue + inferredType: Match[K] extends (p: any) => p is infer R ? R : never + } +} + +type MatcherInferenceValidator = { + [ + K in keyof Match as + Match[K] extends (p: any) => p is infer R + ? R extends CaseValue + ? K + : never + : K + ]: Match[K] +} + +type CaseTypeReader = + Cases[K] extends infer S + ? WhichType< + UnitValue< + S extends Array + ? S[number] + : S + > + > extends 'void' + ? unknown + : UnitValue< + S extends Array + ? S[number] + : S + > + : never + +type CaseValue = + K extends keyof Cases + ? CaseTypeReader + : never + +/** + * Shorthand for creating events attached to store by providing object with reducers for them + * @param store target store + * @param api object with reducers + */ +export function createApi< + S, + Api extends {[name: string]: ((store: S, e: any) => (S | void))} +>( + store: Store, + api: Api, +): { + [K in keyof Api]: ((store: S, e: void) => (S | void)) extends Api[K] + ? Event + : Api[K] extends ((store: S) => (S | void)) + ? Event + : Api[K] extends ((store: S, e: infer E) => (S | void)) + ? Event | void : E> + : any +} + +/** + * Creates a Store out of successful results of Effect. + * It works like a shortcut for `createStore(defaultState).on(effect.done, (_, {result}) => result)` + * @param effect source effect + * @param defaultState initial state of new store + */ +export function restore( + effect: Effect, + defaultState: Done, +): Store +/** + * Creates a Store out of successful results of Effect. + * It works like a shortcut for `createStore(defaultState).on(effect.done, (_, {result}) => result)` + * @param effect source effect + * @param defaultState initial state of new store + */ +export function restore( + effect: Effect, + defaultState: null, +): Store +/** + * Creates a Store from Event. + * It works like a shortcut for `createStore(defaultState).on(event, (_, payload) => payload)` + * @param event source event + * @param defaultState initial state of new store + */ +export function restore(event: Event, defaultState: E): Store +/** + * Creates a Store from Event. + * It works like a shortcut for `createStore(defaultState).on(event, (_, payload) => payload)` + * @param event source event + * @param defaultState initial state of new store + */ +export function restore(event: Event, defaultState: null): Store +export function restore>(event: T): never +export function restore>(effect: T): never +export function restore | any}>( + state: State, +): { + [K in keyof State]: State[K] extends Store + ? Store + : Store +} + +/** + * Creates a domain + */ +export function createDomain(domainName?: string, config?: { domain?: Domain }): Domain +export function createDomain(config?: { name?: string; domain?: Domain }): Domain + +type WhichTypeKind = + | 'never' + | 'any' + | 'unknown' + | 'void' + | 'undefined' + | 'value' +type NotType = Exclude +type WhichType = [T] extends [never] + ? 'never' + : [unknown] extends [T] + ? [0] extends [1 & T] + ? 'any' + : 'unknown' + : [T] extends [void] + ? [void] extends [T] + ? 'void' + : 'undefined' + : 'value' + +type BuiltInObject = + | Error + | Date + | RegExp + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array + | ReadonlyMap + | ReadonlySet + | WeakMap + | WeakSet + | ArrayBuffer + | DataView + | Function + | Promise + | Generator + +type UnitObject = Store | Event | Effect | Unit + +/** + * Force typescript to print real type instead of geneic types + * + * It's better to see {a: string; b: number} + * instead of GetCombinedValue<{a: Store; b: Store}> + * */ +type Show = + A extends BuiltInObject + ? A + : A extends UnitObject + ? A + : { + [K in keyof A]: A[K] + } // & {} + +/* sample types */ +type TupleObject> = { + [I in Exclude]: T[I] +} + +type IfAny = 0 extends (1 & T) ? Y : N; +type IfUnknown = 0 extends (1 & T) ? N : unknown extends T ? Y : N; +type IfAssignable = + (() => IfAny) extends + (() => IfAny) + ? Y + : (T extends U ? never : 1) extends never + ? Y + : T extends Array + ? number extends T['length'] + ? N + : U extends Array + ? number extends U['length'] + ? N + : TupleObject extends TupleObject ? Y : N + : N + : N + +type Source = Unit | Combinable +type Clock = Unit | Tuple> +type Target = Unit | Tuple + +type GetTupleWithoutAny = T extends Array + ? U extends Unit + ? IfAny + : never + : never + +type GetMergedValue = GetTupleWithoutAny extends never ? any : GetTupleWithoutAny + +type GetSource = S extends Unit ? Value : GetCombinedValue +type GetClock = C extends Unit ? Value : GetMergedValue + +/** Replaces incompatible unit type with string error message. + * There is no error message if target type is void. + */ +type ReplaceUnit = IfAssignable + +// [...T] is used to show sample result as a tuple (not array) +type TargetTuple, Result> = [...{ + [Index in keyof Target]: Target[Index] extends Unit + ? ReplaceUnit + : 'non-unit item in target' +}] + +type MultiTarget = Target extends Unit + ? ReplaceUnit + : Target extends Tuple + ? TargetTuple + : 'non-unit item in target' + +type SampleImpl< + Target, + Source, + Clock, + FLBool, + FilterFun, + FN, + FNInf, + FNInfSource extends ( + Source extends Unit | SourceRecord + ? TypeOfSource + : never + ), + FNInfClock extends ( + Clock extends Units + ? TypeOfClock + : never + ), + FNAltArg, + FLUnit, + SomeFN, +> = + // no target + unknown extends Target + // no target, no source + ? unknown extends Source + ? unknown extends Clock + ? [message: {error: 'either target, clock or source should exists'}] + // no target, no source, has clock + : Clock extends Units + ? SampleFilterDef< + ModeSelector< + 'clock | | filter | fn | ', + 'clock | | filter | | ', + 'clock | | | fn | ', + 'clock | | | | ', + SomeFN + >, + Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + // no target, has source + : Source extends Unit | SourceRecord + // no target, has source, no clock + ? unknown extends Clock + ? SampleFilterDef< + ModeSelector< + ' | source | filter | fn | ', + ' | source | filter | | ', + ' | source | | fn | ', + ' | source | | | ', + SomeFN + >, + Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + // no target, has source, has clock + : Clock extends Units + ? SampleFilterDef< + ModeSelector< + 'clock | source | filter | fn | ', + 'clock | source | filter | | ', + 'clock | source | | fn | ', + 'clock | source | | | ', + SomeFN + >, + Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : [message: {error: 'source should be unit or object with stores'; got: Source}] + // has target + : Target extends Units | ReadonlyArray> + // has target, no source + ? unknown extends Source + ? unknown extends Clock + ? [message: {error: 'either target, clock or source should exists'}] + // has target, no source, has clock + : Clock extends Units + ? SampleFilterTargetDef< + ModeSelector< + 'clock | | filter | fn | target', + 'clock | | filter | | target', + 'clock | | | fn | target', + 'clock | | | | target', + SomeFN + >, + Target, Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + // has target, has source + : Source extends Unit | SourceRecord + // has target, has source, no clock + ? unknown extends Clock + ? SampleFilterTargetDef< + ModeSelector< + ' | source | filter | fn | target', + ' | source | filter | | target', + ' | source | | fn | target', + ' | source | | | target', + SomeFN + >, + Target, Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + // has target, has source, has clock + : Clock extends Units + ? SampleFilterTargetDef< + ModeSelector< + 'clock | source | filter | fn | target', + 'clock | source | filter | | target', + 'clock | source | | fn | target', + 'clock | source | | | target', + SomeFN + >, + Target, Source, Clock, FLUnit, FLBool, FilterFun, FN, FNInf, FNInfSource, FNInfClock, FNAltArg, SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : [message: {error: 'source should be unit or object with stores'; got: Source}] + : [message: {error: 'target should be unit or array of units'; got: Target}] + +type ModeSelector< + FilterAndFN, + FilterOnly, + FNOnly, + None, + SomeFN, +> = unknown extends SomeFN + ? FilterAndFN + : SomeFN extends {fn: any; filter: any} + ? FilterAndFN + : SomeFN extends {filter: any} + ? FilterOnly + : SomeFN extends {fn: any} + ? FNOnly + : None + +type SampleRet< + Target, + Source, + Clock, + FLUnit, + FLBool, + FilterFun, + FN, + FNAltArg, + FNInf, + FNInfSource extends ( + Source extends Unit | SourceRecord + ? TypeOfSource + : never + ), + FNInfClock extends ( + Clock extends Units + ? TypeOfClock + : never + ), + SomeFN, + ForceTargetInference +> = unknown extends Target + ? unknown extends Clock + ? unknown extends Source + ? never + : Source extends Unit | SourceRecord + // has filter, has fn + ? unknown extends SomeFN + ? FLUnit extends Unit + ? FN extends (src: TypeOfSource) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>) => any + ? EventAsReturnType> + : never + : FilterFun extends (src: TypeOfSource) => src is FNInfSource + ? FNInf extends (src: FNInfSource) => any + ? EventAsReturnType> + : never + : FN extends (src: TypeOfSource) => any + ? EventAsReturnType> + : never + // has filter, has fn + : SomeFN extends {filter: any; fn: any} + ? FLUnit extends Unit + ? FN extends (src: TypeOfSource) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>) => any + ? EventAsReturnType> + : never + : FilterFun extends (src: TypeOfSource) => src is FNInfSource + ? FNInf extends (src: FNInfSource) => any + ? EventAsReturnType> + : never + : FN extends (src: TypeOfSource) => any + ? EventAsReturnType> + : never + // no filter, has fn + : SomeFN extends {fn: any} + ? FN extends (src: TypeOfSource) => any + ? Source extends Store | SourceRecord + ? Store> + : EventAsReturnType> + : never + // has filter, no fn + : SomeFN extends {filter: any} + ? FLUnit extends Unit + ? EventAsReturnType> + : FLBool extends BooleanConstructor + ? EventAsReturnType>> + : FilterFun extends (src: TypeOfSource) => src is FNInfSource + ? EventAsReturnType + : EventAsReturnType> + // no filter, no fn + : Source extends Store | SourceRecord + ? Store> + : EventAsReturnType> + : never + : unknown extends Source + ? Clock extends Units + // has filter, has fn + ? unknown extends SomeFN + ? FLUnit extends Unit + ? FN extends (clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>) => any + ? EventAsReturnType> + : never + : FilterFun extends (clk: TypeOfClock) => clk is FNInfClock + ? FNInf extends (clk: FNInfClock) => any + ? EventAsReturnType> + : never + : FN extends (clk: TypeOfClock) => any + ? EventAsReturnType> + : never + // has filter, has fn + : SomeFN extends {filter: any; fn: any} + ? FLUnit extends Unit + ? FN extends (clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>) => any + ? EventAsReturnType> + : never + : FilterFun extends (clk: TypeOfClock) => clk is FNInfClock + ? FNInf extends (src: FNInfClock) => any + ? EventAsReturnType> + : never + : FN extends (clk: TypeOfClock) => any + ? EventAsReturnType> + : never + // no filter, has fn + : SomeFN extends {fn: any} + ? FN extends (clk: TypeOfClock) => any + ? Clock extends Store + ? Store> + : EventAsReturnType> + : never + // has filter, no fn + : SomeFN extends {filter: any} + ? FLUnit extends Unit + ? EventAsReturnType> + : FLBool extends BooleanConstructor + ? EventAsReturnType>> + : FilterFun extends (clk: TypeOfClock) => clk is FNInfClock + ? EventAsReturnType + : EventAsReturnType> + // no filter, no fn + : Clock extends Store + ? Store> + : EventAsReturnType> + : never + : Clock extends Units + ? Source extends Unit | SourceRecord + // has filter, has fn + ? unknown extends SomeFN + ? FLUnit extends Unit + ? FN extends (src: TypeOfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FilterFun extends (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + ? FNInf extends (src: FNInfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FN extends (src: TypeOfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + // has filter, has fn + : SomeFN extends {filter: any; fn: any} + ? FLUnit extends Unit + ? FN extends (src: TypeOfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FLBool extends BooleanConstructor + ? FNAltArg extends (arg: NonFalsy>, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FilterFun extends (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + ? FNInf extends (src: FNInfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + : FN extends (src: TypeOfSource, clk: TypeOfClock) => any + ? EventAsReturnType> + : never + // no filter, has fn + : SomeFN extends {fn: any} + ? FN extends (src: TypeOfSource, clk: TypeOfClock) => any + ? [Clock, Source] extends [Store, Store | SourceRecord] + ? Store> + : EventAsReturnType> + : never + // has filter, no fn + : SomeFN extends {filter: any} + ? FLUnit extends Unit + ? EventAsReturnType> + : FLBool extends BooleanConstructor + ? EventAsReturnType>> + : FilterFun extends (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + ? EventAsReturnType + : EventAsReturnType> + // no filter, no fn + : [Clock, Source] extends [Store, Store | SourceRecord] + ? Store> + : EventAsReturnType> + : never + : never + : Target & ForceTargetInference + +/** + * Represents a step in a business logic workflow. It tells an application when it should act, which data it needs, + * how it should be transformed and what should happens next + * + * ```js + * sample({ + * // when clickBuy event is triggered + * clock: clickBuy, + * // read state of $shoppingCart store + * source: $shoppingCart, + * // and if there at least one item in cart + * filter: (cart) => cart.items.length > 0, + * // then select items from cart + * fn: cart => cart.items, + * // and pass results to buyItemsFx effect and clearCart event + * target: [buyItemsFx, clearCart] + * }) + * ``` + */ +export function sample< + Target, + Source, + Clock, + FLBool, + FNInfSource extends ( + Source extends Unit | SourceRecord + ? TypeOfSource + : never + ), + FNInfClock extends ( + Clock extends Units + ? TypeOfClock + : never + ), + FilterFun extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? ( + | never + | ((src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource) + | ((src: TypeOfSource, clk: TypeOfClock) => boolean) + ) + : ( + | never + | ((src: TypeOfSource) => src is FNInfSource) + | ((src: TypeOfSource) => boolean) + ) + : Clock extends Units + ? ( + | never + | ((clk: TypeOfClock) => clk is FNInfClock) + | ((clk: TypeOfClock) => boolean) + ) + : never + ), + FN extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => any + : (src: TypeOfSource) => any + : Clock extends Units + ? (clk: TypeOfClock) => any + : never + ), + FNInf extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: FNInfSource, clk: TypeOfClock) => any + : (src: FNInfSource) => any + : Clock extends Units + ? (clk: FNInfClock) => any + : never + ), + FNNonFalsy extends ( + Source extends Unit | SourceRecord + ? NonFalsy> + : Clock extends Units + ? NonFalsy> + : never + ), + FNAltArg extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: FNNonFalsy, clk: TypeOfClock) => any + : (src: FNNonFalsy) => any + : Clock extends Units + ? (clk: FNNonFalsy) => any + : never + ), + SomeFN, + SourceNoConf, + ClockNoConf, + FNSrcNoConf extends ( + SourceNoConf extends Unit | SourceRecord + ? (src: TypeOfSource) => any + : never + ), + FNBothNoConf extends ( + SourceNoConf extends Unit | SourceRecord + ? ClockNoConf extends Units + ? ((src: TypeOfSource, clk: TypeOfClock) => any) + : never + : never + ), + FLUnit, + Args extends any[], + InferTarget, +>(...args: + SourceNoConf extends Unit | SourceRecord + ? ClockNoConf extends Units + ? [any, any, any] extends Args + ? [source: SourceNoConf, clock: ClockNoConf, fn: FNBothNoConf] & Args + : [any, any] extends Args + ? [source: SourceNoConf, clock: ClockNoConf] & Args + : never + : [any, any] extends Args + ? [source: SourceNoConf, fn: FNSrcNoConf] & Args + : Args extends [Unit] + ? [source: SourceNoConf] & Args + : SampleImpl + : SampleImpl +): SourceNoConf extends Unit | SourceRecord + ? ClockNoConf extends Units + ? [any, any, any] extends Args + ? SourceNoConf extends Store + ? ClockNoConf extends Store + ? Store> + : EventAsReturnType> + : EventAsReturnType> + : [any, any] extends Args + ? SourceNoConf extends Store + ? ClockNoConf extends Store + ? Store> + : EventAsReturnType> + : EventAsReturnType> + : never + : [any, any] extends Args + ? SourceNoConf extends Store + ? Store> + : EventAsReturnType> + : Args extends [Unit] + ? SourceNoConf extends Store + ? Store> + : EventAsReturnType> + : NoInfer> + : NoInfer> + +/* + | 'clock | source | filter | fn | target' + | 'clock | source | | fn | target' + | 'clock | source | filter | fn | ' + | 'clock | source | | fn | ' + | 'clock | source | filter | | target' + | 'clock | source | | | target' + | 'clock | source | filter | | ' + | 'clock | source | | | ' + + | ' | source | filter | fn | target' + | ' | source | | fn | target' + | ' | source | filter | fn | ' + | ' | source | | fn | ' + | ' | source | filter | | target' + | ' | source | | | target' + | ' | source | filter | | ' + | ' | source | | | ' + + | 'clock | | filter | fn | target' + | 'clock | | | fn | target' + | 'clock | | filter | fn | ' + | 'clock | | | fn | ' + | 'clock | | filter | | target' + | 'clock | | | | target' + | 'clock | | filter | | ' + | 'clock | | | | ' +*/ +type Mode_Clk_Src = `clock | source | ${string}`; +type Mode_Clk_NoSrc = `clock | | ${string}`; +type Mode_NoClk_Src = ` | source | ${string}`; +type Mode_Trg = `${string} | target`; +type Mode_Flt_Trg = `${string} | filter | ${string} | target`; +type Mode_NoFlt = `${string} | ${string} | | ${string} | ${string}`; +type Mode_Fn_Trg = `${string} | fn | target`; +type Mode_Src = `${string} | source | ${string}`; +type Mode_Flt_Fn_Trg = `${string} | filter | fn | target`; +type Mode_Src_Flt_NoFn_Trg = `${string} | source | filter | | target`; +type Mode_NoTrg = `${string} | `; +type Mode_Flt = `${string} | filter | ${string}`; +type Mode_Flt_Fn = `${string} | filter | fn | ${string}`; + +type TargetFilterFnConfig< + Mode extends Mode_Flt_Trg, + Target extends Units | ReadonlyArray>, + Source, + Clock, + FilterFun, + FN, +> = Mode extends 'clock | source | filter | fn | target' + ? {clock: Clock; source: Source; filter?: FilterFun; fn?: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | source | filter | | target' + ? {clock: Clock; source: Source; filter: FilterFun; target: Target; greedy?: boolean} + : Mode extends ' | source | filter | fn | target' + ? {source: Source; clock?: never; filter?: FilterFun; fn?: FN; target: Target; greedy?: boolean} + : Mode extends ' | source | filter | | target' + ? {source: Source; clock?: never; filter: FilterFun; target: Target; greedy?: boolean} + : Mode extends 'clock | | filter | fn | target' + ? {clock: Clock; source?: never; filter?: FilterFun; fn?: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | | filter | | target' + ? {clock: Clock; source?: never; filter: FilterFun; target: Target; greedy?: boolean} + : never + +type TargetConfigCheck< + Mode extends Mode_Trg, + Target extends Units | ReadonlyArray>, + Source, + Clock, + FN, + Config, + SomeFN +> = // mode with fn + Mode extends Mode_Fn_Trg + // there should be an explicit conditional selection + // of generic variable for function type + // this could be a reason for a few unfixed implicit any + ? FN extends DataSourceFunction + ? TargetOrError< + ReturnType, + 'fnRet', + Target, + Config & SomeFN + > + : [message: {error: 'function should accept data source types'; got: FN}] + // mode with source only or with both clock and source + : Mode extends Mode_Src + ? Source extends Unit | SourceRecord + ? TargetOrError< + TypeOfSource, + 'src', + Target, + Config & SomeFN + > + : [message: {error: 'source should be unit or object with stores'; got: Source}] + // mode with clock only + : Mode extends Mode_Clk_NoSrc + ? Clock extends Units + ? TargetOrError< + TypeOfClock, + 'clk', + Target, + Config & SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : never + +type InferredType = + Source extends Unit | SourceRecord + ? Clock extends Units + ? FilterFN extends (src: any, clk: TypeOfClock) => src is infer Ret + ? Ret extends TypeOfSource + ? Ret + : never + : never + : FilterFN extends (src: any) => src is infer Ret + ? Ret extends TypeOfSource + ? Ret + : never + : never + : Clock extends Units + ? FilterFN extends (clk: any) => clk is infer Ret + ? Ret extends TypeOfClock + ? Ret + : never + : never + : never + +type SampleFilterTargetDef< + Mode extends Mode_Trg, + Target extends Units | ReadonlyArray>, + Source, + Clock, + FLUnit, + FLBool, + FilterFun, + FN, + FNInf, + FNInfSource extends ( + Source extends Unit | SourceRecord + ? TypeOfSource + : never + ), + FNInfClock extends ( + Clock extends Units + ? TypeOfClock + : never + ), + FNAltArg, + SomeFN +> = Mode extends Mode_Flt_Trg + ? FLUnit extends Unit + ? boolean extends UnitValue + ? FN extends DataSourceFunction + ? TargetConfigCheck< + Mode, Target, Source, Clock, FN, + Mode extends 'clock | source | filter | fn | target' + ? {clock: Clock; source: Source; filter?: FLUnit; fn?: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | source | filter | | target' + ? {clock: Clock; source: Source; filter: FLUnit; target: Target; greedy?: boolean} + : Mode extends ' | source | filter | fn | target' + ? {source: Source; clock?: never; filter?: FLUnit; fn?: FN; target: Target; greedy?: boolean} + : Mode extends ' | source | filter | | target' + ? {source: Source; clock?: never; filter: FLUnit; target: Target; greedy?: boolean} + : Mode extends 'clock | | filter | fn | target' + ? {clock: Clock; source?: never; filter?: FLUnit; fn?: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | | filter | | target' + ? {clock: Clock; source?: never; filter: FLUnit; target: Target; greedy?: boolean} + : never, + SomeFN + > + : [message: {error: 'filter unit should has boolean type'; got: UnitValue}] + : [message: {error: 'function should accept data source types'; got: FN}] + : FLBool extends BooleanConstructor + ? Mode extends Mode_Flt_Fn_Trg + ? FNAltArg extends (arg?: any, clk?: any) => any + ? TargetOrError< + ReturnType, + 'fnRet', + Target, + TargetFilterFnConfig & SomeFN + > + : never + // mode with source only or with both clock and source + : Mode extends Mode_Src_Flt_NoFn_Trg + ? Source extends Unit | SourceRecord + ? TargetOrError< + NonFalsy>, + 'src', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'source should be unit or object with stores'; got: Source}] + // mode with clock only + : Mode extends Mode_Clk_NoSrc + ? Clock extends Units + ? TargetOrError< + NonFalsy>, + 'clk', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : never + : FilterFun extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + : (src: TypeOfSource) => src is FNInfSource + : Clock extends Units + ? (clk: TypeOfClock) => clk is FNInfClock + : never + ) + // mode with fn + ? Mode extends Mode_Flt_Fn_Trg + ? FNInf extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: FNInfSource, clk: TypeOfClock) => any + : (src: FNInfSource) => any + : Clock extends Units + ? (clk: FNInfClock) => any + : any + ) + ? TargetOrError< + ReturnType, + 'fnRet', + Target, + TargetFilterFnConfig | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + : (src: TypeOfSource) => src is FNInfSource + : Clock extends Units + ? (clk: TypeOfClock) => clk is FNInfClock + : never + ), FNInf & ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: FNInfSource, clk: TypeOfClock) => any + : (src: FNInfSource) => any + : Clock extends Units + ? (clk: FNInfClock) => any + : any + )> & SomeFN + > + : [message: {error: 'function should accept data source types'; got: FNInf}] + // mode with source only or with both clock and source + : Mode extends Mode_Src_Flt_NoFn_Trg + ? Source extends Unit | SourceRecord + ? TargetOrError< + InferredType, + 'src', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'source should be unit or object with stores'; got: Source}] + // mode with clock only + : Mode extends Mode_Clk_NoSrc + ? Clock extends Units + ? TargetOrError< + InferredType, + 'clk', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : never + : FilterFun extends ( + Mode extends Mode_Clk_Src + ? Source extends Unit | SourceRecord + ? Clock extends Units + ? ((src: TypeOfSource, clk: TypeOfClock) => any) + : never + : never + : Mode extends Mode_NoClk_Src + ? Source extends Unit | SourceRecord + ? (src: TypeOfSource) => any + : never + : Clock extends Units + ? (clk: TypeOfClock) => any + : never + ) + ? ReturnType extends boolean + // mode with fn + ? Mode extends Mode_Flt_Fn_Trg + ? FN extends DataSourceFunction + ? TargetOrError< + ReturnType, + 'fnRet', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'function should accept data source types'; got: FN}] + // mode with source only or with both clock and source + : Mode extends Mode_Src_Flt_NoFn_Trg + ? Source extends Unit | SourceRecord + ? TargetOrError< + TypeOfSource, + 'src', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'source should be unit or object with stores'; got: Source}] + // mode with clock only + : Mode extends Mode_Clk_NoSrc + ? Clock extends Units + ? TargetOrError< + TypeOfClock, + 'clk', + Target, + TargetFilterFnConfig & SomeFN + > + : [message: {error: 'clock should be unit or array of units'; got: Clock}] + : never + : [message: {error: 'filter function should return boolean'; got: ReturnType}] + : [message: {error: 'filter should be function or unit'; got: FilterFun}] + + : Mode extends Mode_NoFlt + ? FN extends DataSourceFunction + ? TargetConfigCheck< + Mode, Target, Source, Clock, FN, + Mode extends 'clock | source | | fn | target' + ? {clock: Clock; source: Source; filter?: never; fn: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | source | | | target' + ? {clock: Clock; source: Source; filter?: never; target: Target; greedy?: boolean} + : Mode extends ' | source | | fn | target' + ? {source: Source; clock?: never; filter?: never; fn: FN; target: Target; greedy?: boolean} + : Mode extends ' | source | | | target' + ? {source: Source; clock?: never; filter?: never; target: Target; greedy?: boolean} + : Mode extends 'clock | | | fn | target' + ? {clock: Clock; source?: never; filter?: never; fn: FN; target: Target; greedy?: boolean} + : Mode extends 'clock | | | | target' + ? {clock: Clock; source?: never; filter?: never; target: Target; greedy?: boolean} + : never, + SomeFN + > + : [message: {error: 'function should accept data source types'; got: FN}] + : never + +type TargetOrError< + MatchingValue, + Mode extends 'fnRet' | 'src' | 'clk', + Target extends Units | ReadonlyArray>, + ResultConfig +> = [TypeOfTarget] extends [Target] + ? [config: ResultConfig] + : [Target] extends [TypeOfTargetSoft] + ? [config: ResultConfig] + : [message: { + error: Mode extends 'fnRet' + ? 'fn result should extend target type' + : Mode extends 'src' + ? 'source should extend target type' + : 'clock should extend target type' + targets: Show> + }] + +type SampleFilterDef< + Mode extends Mode_NoTrg, + Source, + Clock, + FLUnit, + FLBool, + FilterFun, + FN, + FNInf, + FNInfSource extends ( + Source extends Unit | SourceRecord + ? TypeOfSource + : never + ), + FNInfClock extends ( + Clock extends Units + ? TypeOfClock + : never + ), + FNAltArg, + SomeFN +> = + Mode extends Mode_Flt + ? FLUnit extends Unit + ? boolean extends UnitValue + ? [config: ( + Mode extends 'clock | source | filter | fn | ' + ? {clock: Clock; source: Source; filter?: FLUnit; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | source | filter | | ' + ? {clock: Clock; source: Source; filter: FLUnit; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | fn | ' + ? {source: Source; clock?: never; filter?: FLUnit; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | | ' + ? {source: Source; clock?: never; filter: FLUnit; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | fn | ' + ? {clock: Clock; source?: never; filter?: FLUnit; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | | ' + ? {clock: Clock; source?: never; filter: FLUnit; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : [message: {error: 'filter unit should has boolean type'; got: UnitValue}] + : FLBool extends BooleanConstructor + ? Mode extends Mode_Flt_Fn + ? [config: ( + Mode extends 'clock | source | filter | fn | ' + ? {clock: Clock; source: Source; filter?: FLBool; fn?: FNAltArg; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | fn | ' + ? {source: Source; clock?: never; filter?: FLBool; fn?: FNAltArg; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | fn | ' + ? {clock: Clock; source?: never; filter?: FLBool; fn?: FNAltArg; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : [config: ( + Mode extends 'clock | source | filter | | ' + ? {clock: Clock; source: Source; filter: FLBool; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | | ' + ? {source: Source; clock?: never; filter: FLBool; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | | ' + ? {clock: Clock; source?: never; filter: FLBool; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : FilterFun extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => src is FNInfSource + : (src: TypeOfSource) => src is FNInfSource + : Clock extends Units + ? (clk: TypeOfClock) => clk is FNInfClock + : never + ) + ? Mode extends Mode_Flt_Fn + ? FNInf extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: FNInfSource, clk: TypeOfClock) => any + : (src: FNInfSource) => any + : Clock extends Units + ? (clk: FNInfClock) => any + : any + ) + ? [config: ( + Mode extends 'clock | source | filter | fn | ' + ? {clock: Clock; source: Source; filter?: FilterFun; fn?: FNInf; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | fn | ' + ? {source: Source; clock?: never; filter?: FilterFun; fn?: FNInf; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | fn | ' + ? {clock: Clock; source?: never; filter?: FilterFun; fn?: FNInf; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : [message: { + error: 'fn should match inferred type' + inferred: (Source extends Unit | SourceRecord ? FNInfSource : FNInfClock) + fnArg: FNInf extends (arg: infer Arg) => any ? Arg : never + }] + : [config: ( + Mode extends 'clock | source | filter | | ' + ? {clock: Clock; source: Source; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | | ' + ? {source: Source; clock?: never; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | | ' + ? {clock: Clock; source?: never; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : FilterFun extends ( + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => any + : (src: TypeOfSource) => any + : Clock extends Units + ? (clk: TypeOfClock) => any + : never + ) + ? ReturnType extends boolean + ? [config: ( + Mode extends 'clock | source | filter | fn | ' + ? {clock: Clock; source: Source; filter?: FilterFun; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | source | filter | | ' + ? {clock: Clock; source: Source; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | fn | ' + ? {source: Source; clock?: never; filter?: FilterFun; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | filter | | ' + ? {source: Source; clock?: never; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | fn | ' + ? {clock: Clock; source?: never; filter?: FilterFun; fn?: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | filter | | ' + ? {clock: Clock; source?: never; filter: FilterFun; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : [message: {error: 'filter function should return boolean'; got: ReturnType}] + : [message: {error: 'filter should be function or unit'; got: FilterFun}] + : Mode extends Mode_NoFlt + ? [config: ( + Mode extends 'clock | source | | fn | ' + ? {clock: Clock; source: Source; filter?: never; fn: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | source | | | ' + ? {clock: Clock; source: Source; filter?: never; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | | fn | ' + ? {source: Source; clock?: never; filter?: never; fn: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends ' | source | | | ' + ? {source: Source; clock?: never; filter?: never; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | | fn | ' + ? {clock: Clock; source?: never; filter?: never; fn: FN; target?: never; greedy?: boolean; name?: string} + : Mode extends 'clock | | | | ' + ? {clock: Clock; source?: never; filter?: never; target?: never; greedy?: boolean; name?: string} + : never + ) & SomeFN] + : never + +type DataSourceFunction = + Source extends Unit | SourceRecord + ? Clock extends Units + ? (src: TypeOfSource, clk: TypeOfClock) => any + : (src: TypeOfSource) => any + : Clock extends Units + ? (clk: TypeOfClock) => any + : never + +type TypeOfTargetSoft>, Mode extends 'fnRet' | 'src' | 'clk'> = + Target extends Unit + ? Target extends Unit + ? [SourceType] extends [Readonly] + ? Target + : WhichType extends ('void' | 'any') + ? Target + : IfAssignable + : never + : { + [ + K in keyof Target + ]: Target[K] extends Unit + ? [SourceType] extends [Readonly] + ? Target[K] + : WhichType extends ('void' | 'any') + ? Target[K] + : IfAssignable + : never + } + +type TypeOfTarget>, Mode extends 'fnRet' | 'src' | 'clk'> = + Target extends Unit + ? Target extends Unit + ? [SourceType] extends [Readonly] + ? Target + : WhichType extends ('void' | 'any') + ? Target + : Mode extends 'fnRet' + ? {fnResult: SourceType; targetType: TargetType} + : Mode extends 'src' + ? {sourceType: SourceType; targetType: TargetType} + : {clockType: SourceType; targetType: TargetType} + : never + : { + [ + K in keyof Target + ]: Target[K] extends Unit + ? [SourceType] extends [Readonly] + ? Target[K] + : WhichType extends ('void' | 'any') + ? Target[K] + : Mode extends 'fnRet' + ? {fnResult: SourceType; targetType: TargetType} + : Mode extends 'src' + ? {sourceType: SourceType; targetType: TargetType} + : {clockType: SourceType; targetType: TargetType} + : never + } + +type ClockValueOf = T[keyof T] + +type TypeOfSource | SourceRecord> = + Source extends Unit + ? UnitValue + : Source extends SourceRecord + ? {[K in keyof Source]: UnitValue} + : never + +type TypeOfClock> | never[]> = + Clock extends never[] + ? unknown + : Clock extends Unit + ? UnitValue + : Clock extends Tuple> + ? WhichType> extends 'any' + ? never + : K + ]: Clock[K] + }>>> extends 'never' + ? any + : UnitValue> extends 'any' + ? never + : K + ]: Clock[K] + }>> + : Clock extends ReadonlyArray> + ? UnitValue> + : never + +type SourceRecord = Record> | RoTuple> + +type Units = Unit | Tuple> + +/* guard types */ + +type NonFalsy = T extends null | undefined | false | 0 | 0n | "" ? never : T; + +type GuardFilterSC = + | ((source: GetSource, clock: GetClock) => boolean) + | Store +type GuardFilterS = + | ((source: GetSource) => boolean) + | Store +type GuardFilterC = + | ((clock: GetClock) => boolean) + | Store + +type GuardResult = EventAsReturnType + +type GetGuardSource = F extends BooleanConstructor + ? NonFalsy> + : GetSource +type GetGuardClock = F extends BooleanConstructor + ? NonFalsy> + : GetClock + +// --------------------------------------- +/* user-defined typeguard: with target */ +// SСT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, B = any, + S extends Source = Source, + C extends Clock = Clock, + T extends Target = Target +>(config: { + source: S, + clock: C, + filter: (source: GetSource, clock: GetClock) => source is X, + target: MultiTarget, + name?: string, + greedy?: boolean +}): T +// ST +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + S extends Source = Source, + T extends Target = Target +>(config: { + source: S, + filter: (source: GetSource) => source is X, + target: MultiTarget, + name?: string, + greedy?: boolean +}): T +// СT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + C extends Clock = Clock, + T extends Target = Target +>(config: { + clock: C, + filter: (clock: GetClock) => clock is X, + target: MultiTarget, + name?: string, + greedy?: boolean +}): T + +/* user-defined typeguard: without target */ +// SC +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, B = any, + S extends Source = Source, + C extends Clock = Clock +>(config: { + source: S, + clock: C, + filter: (source: GetSource, clock: GetClock) => source is X, + name?: string, + greedy?: boolean +}): GuardResult +// S +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + S extends Source = Source +>(config: { + source: S, + filter: (source: GetSource) => source is X, + name?: string, + greedy?: boolean +}): GuardResult +// C +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + C extends Clock = Clock +>(config: { + clock: C, + filter: (clock: GetClock) => clock is X, + name?: string, + greedy?: boolean +}): GuardResult + +// --------------------------------------- +/* boolean fn or store: with target */ +// SСT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + C extends Clock = Clock, + F extends GuardFilterSC = GuardFilterSC, + T extends Target = Target +>(config: { + source: S, + clock: C, + filter: F, + target: MultiTarget>, + name?: string, + greedy?: boolean +}): T +// ST +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + F extends GuardFilterS = GuardFilterS, + T extends Target = Target +>(config: { + source: S, + filter: F, + target: MultiTarget>, + name?: string, + greedy?: boolean +}): T +// СT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Clock, + F extends GuardFilterC = GuardFilterC, + T extends Target = Target +>(config: { + clock: C, + filter: F, + target: MultiTarget>, + name?: string, + greedy?: boolean +}): T + +/* boolean fn or store: without target */ +// SC (units: BooleanConstructor) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + source: Unit, + clock: Unit, + filter: BooleanConstructor, + name?: string, + greedy?: boolean +}): GuardResult> +// SC (units: boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + source: Unit, + clock: Unit, + filter: ((source: A, clock: B) => boolean) | Store, + name?: string, + greedy?: boolean +}): GuardResult +// SC +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + C extends Clock = Clock, + F extends GuardFilterSC = GuardFilterSC, +>(config: { + source: S, + clock: C, + filter: F, + name?: string, + greedy?: boolean +}): GuardResult> +// S (unit: BooleanConstructor) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + source: Unit, + filter: BooleanConstructor, + name?: string, + greedy?: boolean +}): GuardResult> +// S (unit - boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + source: Unit, + filter: ((source: A) => boolean) | Store, + name?: string, + greedy?: boolean +}): GuardResult +// S +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + F extends GuardFilterS = GuardFilterS, +>(config: { + source: S, + filter: F, + name?: string, + greedy?: boolean +}): GuardResult> +// C (unit: boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + clock: Unit, + filter: BooleanConstructor, + name?: string, + greedy?: boolean +}): GuardResult> +// C (unit: boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(config: { + clock: Unit, + filter: ((clock: B) => boolean) | Store, + name?: string, + greedy?: boolean +}): GuardResult +// C +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Clock, + F extends GuardFilterC = GuardFilterC, +>(config: { + clock: C, + filter: F, + name?: string, + greedy?: boolean +}): GuardResult> + +// --------------------------------------- +// guard with source param +// --------------------------------------- + +/* user-defined typeguard: with target */ +// SСT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, B = any, + S extends Source = Source, + C extends Clock = Clock, + T extends Target = Target +>(source: S, config: { + clock: C, + filter: (source: GetSource, clock: GetClock) => source is X, + target: MultiTarget, + name?: string, + greedy?: boolean +}): T +// ST +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + S extends Source = Source, + T extends Target = Target +>(source: S, config: { + filter: (source: GetSource) => source is X, + target: MultiTarget, + name?: string, + greedy?: boolean +}): T + +/* user-defined typeguard: without target */ +// SC +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, B = any, + S extends Source = Source, + C extends Clock = Clock +>(source: S, config: { + clock: C, + filter: (source: GetSource, clock: GetClock) => source is X, + name?: string, + greedy?: boolean +}): GuardResult +// S +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard, + S extends Source = Source +>(source: S, config: { + filter: (source: GetSource) => source is X, + name?: string, + greedy?: boolean +}): GuardResult + +// --------------------------------------- +/* boolean fn or store: with target */ +// SСT +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + C extends Clock = Clock, + F extends GuardFilterSC = GuardFilterSC, + T extends Target = Target +>(source: S, config: { + clock: C, + filter: F, + target: MultiTarget>, + name?: string, + greedy?: boolean +}): T +// ST +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + F extends GuardFilterS = GuardFilterS, + T extends Target = Target +>(source: S, config: { + filter: F, + target: MultiTarget>, + name?: string, + greedy?: boolean +}): T + +/* boolean fn or store: without target */ +// SC (units: BooleanConstructor) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(source: Unit, config: { + clock: Unit, + filter: BooleanConstructor, + name?: string, + greedy?: boolean +}): GuardResult> +// SC (units: boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(source: Unit, config: { + clock: Unit, + filter: ((source: A, clock: B) => boolean) | Store, + name?: string, + greedy?: boolean +}): GuardResult +// SC +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + C extends Clock = Clock, + F extends GuardFilterSC = GuardFilterSC, +>(source: S, config: { + clock: C, + filter: F, + name?: string, + greedy?: boolean +}): GuardResult> +// S (unit: BooleanConstructor) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(source: Unit, config: { + filter: BooleanConstructor, + name?: string, + greedy?: boolean +}): GuardResult> +// S (unit: boolean fn or store) +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard(source: Unit, config: { + filter: ((source: A) => boolean) | Store, + name?: string, + greedy?: boolean +}): GuardResult +// S +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard = Source, + F extends GuardFilterS = GuardFilterS, +>(source: S, config: { + filter: F, + name?: string, + greedy?: boolean +}): GuardResult> + +// guard's last overload for `guard(source, config)` +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard< + S extends Source, + C extends Clock, + F extends IfUnknown, + Store | ((clock: GetClock) => boolean), + IfUnknown, + Store | ((source: GetSource) => boolean), + Store | ((source: GetSource, clock: GetClock) => boolean) + > + >, + T extends Target +>(source: S, config: { + clock?: C, + filter: F, + target: F extends (value: any, ...args: any) => value is infer X + ? MultiTarget + : MultiTarget>, + name?: string, + greedy?: boolean +}): T + +// guard's last overload for `guard(config)` +/** + * Method for conditional event routing. + * > Superseded by `sample({clock, source, filter, fn, target})` + */ +export function guard< + S extends Source, + C extends Clock, + F extends IfUnknown, + Store | ((clock: GetClock) => boolean), + IfUnknown, + Store | ((source: GetSource) => boolean), + Store | ((source: GetSource, clock: GetClock) => boolean) + > + >, + T extends Target +>(config: { + source?: S, + clock?: C, + filter: F, + target: F extends (value: any, ...args: any) => value is infer X + ? MultiTarget + : MultiTarget, + GetGuardClock, + GetGuardSource + > + >, + name?: string, + greedy?: boolean +}): T + +/* attach types */ + +type StoreShape = Store | Combinable +type GetShapeValue = T extends Store ? S : GetCombinedValue + +/** + * Method for creating state-dependent effect and transforming effect payloads + * @returns new effect + */ +export function attach< + Params, + States extends StoreShape, + FX extends Effect +>(config: { + source: States + effect: FX + mapParams: (params: Params, states: GetShapeValue) => NoInfer> + name?: string +}): Effect, EffectError> +/** + * Method for transforming effect payloads + * @returns new effect + */ +export function attach any), FX extends Effect>(config: { + effect: FX + mapParams: FN extends (...args: any[]) => NoInfer> + ? FN + : never + name?: string +}): FN extends (...args: infer Args) => NoInfer> + ? Effect< + Args['length'] extends 0 + ? void + : 0 | 1 extends Args['length'] + ? Args[0] | void + : Args[0], + EffectResult, + EffectError + > + : never +/** + * Method for transforming effect payloads + * @returns new effect + */ +export function attach>(config: { + effect: FX + mapParams: (params: Params) => NoInfer> + name?: string +}): Effect, EffectError> +/** + * Method for passing state values to effects + * @returns new effect + */ +export function attach< + States extends StoreShape, + FX extends Effect, any, any> +>(config: { + source: States + effect: FX + name?: string +}): Effect, EffectError> +/** + * Creates state-dependent effect with provided function handler. + * Allows the one to omit intermediate effects and declare effect handler right next to data source + * @returns new effect + */ +export function attach< + States extends StoreShape, + FX extends (state: GetShapeValue, params: any) => any +>(config: { + source: States + effect: FX + name?: string +}): FX extends (source: any, ...args: infer Args) => infer Done + ? Effect, AsyncResult> + : never +/** + * Creates independent instance of given effect. Used to add subscribers to effect call in a particular business case + * @returns new effect linked to given one + */ +export function attach< + FX extends Effect, +>(config: { + effect: FX +}): Effect, EffectResult, EffectError> +/** + * Method for creating state-dependent effect and transforming effect payload + * @returns new effect + */ +export function attach< + States extends StoreShape, + FX extends Effect, + FN extends ((params: any, source: GetShapeValue) => NoInfer>) +>(config: { + source: States + effect: FX + mapParams: FN + name?: string +}): Effect[0] , EffectResult, EffectError> + +type CombineState = State[keyof State] extends Store + // ensure that CombineState will be used only with explicit generics + // without Store type in them + ? never + : { + [K in keyof State]: + | State[K] + | (undefined extends State[K] + ? Store> + : Store) +} + +/** + * Bind units and links between them created inside `cb` callback to unit or graph node to erase during `clearNode` call + * Low level tool, usually absent in common applications + * @param unit parent unit or graph node + * @param cb callback assumed to create some units + */ +export function withRegion(unit: Unit | Node, cb: () => T): T + +/** + * Helper type for combine + */ +type CombVal = T extends Store ? StoreValue : T + +/** + * Convert given stores to store with array which values updated upon changes in given ones + * @returns derived store + */ +export function combine>( + store: T, +): T extends Store ? Store<[R]> : never +/** + * Convert array of stores to store with array which values updated upon changes in given ones + * @param tuple array of stores + * @returns derived store updated upon changes in given ones + */ +export function combine( + tuple: State, +): Store<{[K in keyof State]: State[K] extends Store ? U : State[K]}> +/** + * Convert object with stores to object store which fields updated upon changes in given ones + * @param shape object with stores + * @returns derived store updated upon changes in given ones + */ +export function combine(shape: CombineState): Store +/** + * Convert object with stores to object store which fields updated upon changes in given ones + * @param shape object with stores + * @returns derived store updated upon changes in given ones + */ +export function combine( + shape: State, +): Store<{[K in keyof State]: State[K] extends Store ? U : State[K]}> +/** + * Creates derived store from given one, transforming value using the function + * @param source source store + * @param fn transformer function, accepts a store value + * @returns derived store updated upon changes in given one + */ +export function combine(source: Store, fn: (source: A) => R): Store +/** + * Convert array of stores into derived store, transforming values using the function + * @param tuple array of stores + * @param fn transformer function, accepts an array of values + * @returns derived store updated upon changes in given ones + */ +export function combine( + tuple: State, + fn: ( + tuple: {[K in keyof State]: State[K] extends Store ? U : State[K]}, + ) => R, +): Store +/** + * Convert object with stores into derived store, transforming values using the function + * @param shape object with stores + * @param fn transformer function, accepts object with values + * @returns derived store updated upon changes in given ones + */ +export function combine( + shape: State, + fn: ( + shape: {[K in keyof State]: State[K] extends Store ? U : State[K]}, + ) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + fn: (a: CombVal, b: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + fn: (a: CombVal, b: CombVal, c: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal, g: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * + * > Consider using `combine(arrayOfStores, arrayOfValues => ...)` instead + * + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal, g: CombVal, h: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * + * > Consider using `combine(arrayOfStores, arrayOfValues => ...)` instead + * + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal, g: CombVal, h: CombVal, i: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * + * > Consider using `combine(arrayOfStores, arrayOfValues => ...)` instead + * + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal, g: CombVal, h: CombVal, i: CombVal, j: CombVal) => R, +): Store +/** + * Convert given stores into derived store, transforming values using the function + * + * > Consider using `combine(arrayOfStores, arrayOfValues => ...)` instead + * + * @param fn transformer function, accepts store values in separate arguments + * @returns derived store updated upon changes in given ones + */ +export function combine( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + k: K, + fn: (a: CombVal, b: CombVal, c: CombVal, d: CombVal, e: CombVal, f: CombVal, g: CombVal, h: CombVal, i: CombVal, j: CombVal, k: CombVal) => R, +): Store +/** + * Convert given stores to store with array which values updated upon changes in given ones + * @returns derived store + */ +export function combine | any>>( + ...stores: T +): Store<{[K in keyof T]: T[K] extends Store ? U : T[K]}> + +/** + * Fully isolated instance of application. The primary purpose of scope includes SSR and testing + */ +export interface Scope extends Unit { + getState(store: Store): T +} + +export type ValueMap = Map, any> | Array<[Store, any]> | {[sid: string]: any} + +/** + * Fill stores with given values in provided scope or domain + */ +export function hydrate(domainOrScope: Domain | Scope, config: {values: ValueMap}): void + +/** + * Serialize store values from given scope + * @returns object with saved values + */ +export function serialize( + scope: Scope, + options?: {ignore?: Array>; onlyChanges?: boolean}, +): {[sid: string]: any} + +/** + * Bind event to a scope to be called later. + * + * When `scope` is not provided this method retrieve scope implicitly from scope of the handler (effect handler or watch function) inside which it's being called + * @param unit event to bind + * @returns function which will trigger an event in a given scope + */ +export function scopeBind(unit: Event, opts?: {scope?: Scope; safe?: boolean}): (payload: T) => void +/** + * Bind effect to a scope to be called later. + * + * When `scope` is not provided this method retrieve scope implicitly from scope of the handler (effect handler or watch function) inside which it's being called + * @param unit effect to bind + * @returns function which will trigger an effect in a given scope and returns a promise with a result + */ +export function scopeBind(unit: Effect, opts?: {scope?: Scope; safe?: boolean}): (params: P) => Promise + +/** + * Creates isolated instance of application. Primary purposes of this method are SSR and testing. + * @param domain optional root domain + * @param config optional configuration object with initial store values and effect handlers + * @returns new scope + */ +export function fork( + domain: Domain, + config?: { + values?: ValueMap + handlers?: Map, Function> | Array<[Effect, Function]> | {[sid: string]: Function} + }, +): Scope +/** + * Creates isolated instance of application. Primary purposes of this method are SSR and testing. + * @param config optional configuration object with initial store values and effect handlers + * @returns new scope + */ +export function fork( + config?: { + values?: ValueMap + handlers?: Map, Function> | Array<[Effect, Function]> | {[sid: string]: Function} + }, +): Scope + +/** + * Run effect in scope and wait for all triggered effects to settle. This method never throw an error + * @param unit effect to run + * @returns promise with status object for given effect, will resolve when there will be no pending effects in given scope + */ +export function allSettled>( + unit: FX, + config: {scope: Scope; params: EffectParams}, +): Promise<{status: 'done', value: EffectResult} | {status: 'fail'; value: EffectError}> +/** + * Run effect withot arguments in scope and wait for all triggered effects to settle. This method never throw an error + * @param unit effect to run + * @returns promise with status object for given effect, will resolve when there will be no pending effects in given scope + */ +export function allSettled>( + unit: FX, + config: {scope: Scope}, +): Promise<{status: 'done', value: EffectResult} | {status: 'fail'; value: EffectError}> +/** + * Run unit in scope and wait for all triggered effects to settle. This method never throw an error + * @param unit event or store to run + * @returns void promise, will resolve when there will be no pending effects in given scope + */ +export function allSettled( + unit: Unit, + config: {scope: Scope; params: T}, +): Promise +/** + * Run unit without arguments in scope and wait for all triggered effects to settle. This method never throw an error + * @param unit event or store to run + * @returns void promise, will resolve when there will be no pending effects in given scope + */ +export function allSettled( + unit: Unit, + config: {scope: Scope}, +): Promise +/** + * Check for any ongoing computations in provided scope and wait for them to settle. + * @param scope {Scope} + * @returns void promise, will resolve when there will be no pending effects in given scope + */ +export function allSettled(scope: Scope): Promise + +export function createWatch({ + unit, + fn, + scope, +}: { + unit: Unit + fn: (value: T) => any + scope?: Scope +}): Subscription