selector test is passing

This commit is contained in:
Yanick Champoux 2023-03-10 12:04:19 -05:00
parent c660b7be1d
commit 7a5733425e
3 changed files with 40 additions and 9 deletions

View File

@ -12,7 +12,7 @@ import {
ActionCreatorWithoutPayload, ActionCreatorWithoutPayload,
ActionCreatorWithPreparedPayload, ActionCreatorWithPreparedPayload,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import { AggregateActions, Dux } from './types.js'; import { AggregateActions, AggregateSelectors, Dux } from './types.js';
import { buildActions } from './buildActions.js'; import { buildActions } from './buildActions.js';
import { buildInitial, AggregateState } from './initial.js'; import { buildInitial, AggregateState } from './initial.js';
import { buildReducer, MutationCase } from './reducer.js'; import { buildReducer, MutationCase } from './reducer.js';
@ -51,8 +51,6 @@ export type Mutation<A extends Action<any> = Action<any>, S = any> = (
action: A, action: A,
) => (state: S) => S | void; ) => (state: S) => S | void;
export type AggregateSelectors<S> = S;
type SelectorForState<S> = (state: S) => unknown; type SelectorForState<S> = (state: S) => unknown;
type SelectorsForState<S> = { type SelectorsForState<S> = {
[key: string]: SelectorForState<S>; [key: string]: SelectorForState<S>;
@ -84,8 +82,7 @@ export default class Updux<
string, string,
(state: AggregateState<T_LocalState, T_Subduxes>) => any (state: AggregateState<T_LocalState, T_Subduxes>) => any
>; >;
#selectors: any;
#selectors: AggregateSelectors<T_LocalSelectors>;
constructor( constructor(
config: Partial<{ config: Partial<{
@ -104,6 +101,16 @@ export default class Updux<
this.#initial = buildInitial(this.#localInitial, this.#subduxes); this.#initial = buildInitial(this.#localInitial, this.#subduxes);
this.#localSelectors = config.selectors; this.#localSelectors = config.selectors;
const basedSelectors = R.mergeAll(
Object.entries(this.#subduxes)
.filter(([slice, { selectors }]) => selectors)
.map(([slice, { selectors }]) =>
R.mapValues(selectors, (s) => (state) => s(state[slice])),
),
);
this.#selectors = R.merge(basedSelectors, this.#localSelectors);
} }
get actions() { get actions() {
@ -129,8 +136,12 @@ export default class Updux<
return store; return store;
} }
get selectors(): T_LocalSelectors { get selectors(): AggregateSelectors<
return this.#localSelectors as any; T_LocalSelectors,
T_Subduxes,
AggregateState<T_LocalState, T_Subduxes>
> {
return this.#selectors as any;
} }
// TODO memoize this sucker // TODO memoize this sucker

View File

@ -22,6 +22,11 @@ test('basic selectors', () => {
}, },
}); });
expect(foo.selectors.getY({ bar: { y: 3 } } as typeof foo.initial)).toBe(3); const sample = {
expect(foo.selectors.getX({ x: 4 } as typeof foo.initial)).toBe(4); x: 4,
bar: { y: 3 },
};
expect(foo.selectors.getY(sample)).toBe(3);
expect(foo.selectors.getX(sample)).toBe(4);
}); });

View File

@ -6,6 +6,7 @@ export type Dux<
> = Partial<{ > = Partial<{
initial: STATE; initial: STATE;
actions: ACTIONS; actions: ACTIONS;
selectors: Record<string, (state: STATE) => any>;
reducer: ( reducer: (
state: STATE, state: STATE,
action: ReturnType<ACTIONS[keyof ACTIONS]>, action: ReturnType<ACTIONS[keyof ACTIONS]>,
@ -13,11 +14,25 @@ export type Dux<
}>; }>;
type ActionsOf<DUX> = DUX extends { actions: infer A } ? A : {}; type ActionsOf<DUX> = DUX extends { actions: infer A } ? A : {};
type SelectorsOf<DUX> = DUX extends { selectors: infer A } ? A : {};
export type AggregateActions<A, S> = UnionToIntersection< export type AggregateActions<A, S> = UnionToIntersection<
ActionsOf<S[keyof S]> | A ActionsOf<S[keyof S]> | A
>; >;
type BaseSelector<F extends (...args: any) => any, STATE> = (
state: STATE,
) => ReturnType<F>;
type BaseSelectors<S, STATE> = {
[key in keyof S]: BaseSelector<S[key], STATE>;
};
export type AggregateSelectors<S, SUBS, STATE = {}> = BaseSelectors<
UnionToIntersection<SelectorsOf<SUBS[keyof SUBS]> | S>,
STATE
>;
export type UnionToIntersection<U> = ( export type UnionToIntersection<U> = (
U extends any ? (k: U) => void : never U extends any ? (k: U) => void : never
) extends (k: infer I) => void ) extends (k: infer I) => void