84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
import { ActionCreator, ActionCreatorWithPreparedPayload, AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit';
|
|
import { EffectMiddleware } from './effects.js';
|
|
import Updux from './Updux.js';
|
|
export type DuxConfig = Partial<{
|
|
initialState: any;
|
|
subduxes: Record<string, DuxConfig>;
|
|
actions: Record<string, ActionCreator<string> | Function | null>;
|
|
selectors: Record<string, Function>;
|
|
effects: EffectMiddleware<any>[];
|
|
reactions: DuxReaction<any>[];
|
|
reducer: (state: any, action: AnyAction) => any;
|
|
}>;
|
|
type UpduxConfig<D> = D extends Updux<infer T> ? T : D;
|
|
export type SubduxesState<D> = D extends {
|
|
subduxes: infer S;
|
|
} ? {
|
|
[key in keyof S]: DuxState<UpduxConfig<S[key]>>;
|
|
} : unknown;
|
|
type ForceResolveObject<O> = O extends {
|
|
[key: string]: any;
|
|
} ? {
|
|
[key in keyof O]: O[key];
|
|
} : O;
|
|
export type DuxState<D> = ForceResolveObject<(D extends {
|
|
initialState: any;
|
|
} ? D['initialState'] : {}) & (D extends {
|
|
subduxes: any;
|
|
} ? SubduxesState<D> : unknown)>;
|
|
type SubduxesActions<D> = D extends {
|
|
subduxes: infer S;
|
|
} ? UnionToIntersection<DuxActions<UpduxConfig<S[keyof S]>>> : unknown;
|
|
type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
|
|
type IsAny<T> = IfAny<T, true, never>;
|
|
type ResolveAction<K extends string, A> = true extends IsAny<A> ? ActionCreator<A> : A extends Function & {
|
|
type: string;
|
|
} ? A : A extends (...args: infer PARAMS) => infer R ? ActionCreatorWithPreparedPayload<PARAMS, R, K, never, never> : ActionCreator<A>;
|
|
type ResolveActions<A> = A extends {
|
|
[key: string]: any;
|
|
} ? {
|
|
[key in keyof A]: key extends string ? ResolveAction<key, A[key]> : never;
|
|
} : A;
|
|
export type DuxActions<D> = ResolveActions<(D extends {
|
|
actions: any;
|
|
} ? D['actions'] : {}) & (D extends {
|
|
subduxes: any;
|
|
} ? SubduxesActions<D> : unknown)>;
|
|
export type Subduxes = Record<string, Updux<any> | DuxConfig>;
|
|
export type MutationEntry<S = any> = {
|
|
terminal: boolean;
|
|
matcher?: (action: AnyAction) => boolean;
|
|
mutation: Mutation<AnyAction, S>;
|
|
};
|
|
export type Mutation<A = AnyAction, S = any> = (payload: A extends {
|
|
payload: infer P;
|
|
} ? P : undefined, action: A) => (state: S) => S | void;
|
|
type CurriedSelectors<S> = {
|
|
[key in keyof S]: CurriedSelector<S[key]>;
|
|
};
|
|
type XSel<R> = R extends Function ? R : () => R;
|
|
type CurriedSelector<S> = S extends (...args: any) => infer R ? XSel<R> : never;
|
|
export type AugmentedMiddlewareAPI<D> = MiddlewareAPI<Dispatch<AnyAction>, DuxState<D>> & {
|
|
dispatch: DuxActions<D>;
|
|
getState: CurriedSelectors<DuxSelectors<D>>;
|
|
actions: DuxActions<D>;
|
|
selectors: DuxSelectors<D>;
|
|
};
|
|
export type DuxSelectors<D> = ForceResolveObject<(D extends {
|
|
selectors: infer S;
|
|
} ? S : {}) & (D extends {
|
|
subduxes: infer SUB;
|
|
} ? UnionToIntersection<Values<{
|
|
[key in keyof SUB]: RebaseSelectors<key, SUB[key]>;
|
|
}>> : {})>;
|
|
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
type RebaseSelectors<SLICE, DUX> = DUX extends {
|
|
selectors: infer S;
|
|
} ? {
|
|
[key in keyof S]: RebaseSelector<SLICE, S[key]>;
|
|
} : never;
|
|
type RebaseSelector<SLICE, S> = SLICE extends string ? S extends (state: infer STATE) => infer R ? (state: Record<SLICE, STATE>) => R : never : never;
|
|
type Values<X> = X[keyof X];
|
|
export type DuxReaction<D extends DuxConfig> = (api: AugmentedMiddlewareAPI<D>) => (state: DuxState<D>, previousState: DuxState<D> | undefined, unsubscribe: () => void) => void;
|
|
export {};
|