selector test is passing

main
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,
ActionCreatorWithPreparedPayload,
} from '@reduxjs/toolkit';
import { AggregateActions, Dux } from './types.js';
import { AggregateActions, AggregateSelectors, Dux } from './types.js';
import { buildActions } from './buildActions.js';
import { buildInitial, AggregateState } from './initial.js';
import { buildReducer, MutationCase } from './reducer.js';
@ -51,8 +51,6 @@ export type Mutation<A extends Action<any> = Action<any>, S = any> = (
action: A,
) => (state: S) => S | void;
export type AggregateSelectors<S> = S;
type SelectorForState<S> = (state: S) => unknown;
type SelectorsForState<S> = {
[key: string]: SelectorForState<S>;
@ -84,8 +82,7 @@ export default class Updux<
string,
(state: AggregateState<T_LocalState, T_Subduxes>) => any
>;
#selectors: AggregateSelectors<T_LocalSelectors>;
#selectors: any;
constructor(
config: Partial<{
@ -104,6 +101,16 @@ export default class Updux<
this.#initial = buildInitial(this.#localInitial, this.#subduxes);
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() {
@ -129,8 +136,12 @@ export default class Updux<
return store;
}
get selectors(): T_LocalSelectors {
return this.#localSelectors as any;
get selectors(): AggregateSelectors<
T_LocalSelectors,
T_Subduxes,
AggregateState<T_LocalState, T_Subduxes>
> {
return this.#selectors as any;
}
// 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);
expect(foo.selectors.getX({ x: 4 } as typeof foo.initial)).toBe(4);
const sample = {
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<{
initial: STATE;
actions: ACTIONS;
selectors: Record<string, (state: STATE) => any>;
reducer: (
state: STATE,
action: ReturnType<ACTIONS[keyof ACTIONS]>,
@ -13,11 +14,25 @@ export type Dux<
}>;
type ActionsOf<DUX> = DUX extends { actions: infer A } ? A : {};
type SelectorsOf<DUX> = DUX extends { selectors: infer A } ? A : {};
export type AggregateActions<A, S> = UnionToIntersection<
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> = (
U extends any ? (k: U) => void : never
) extends (k: infer I) => void