selector test is passing
This commit is contained in:
parent
c660b7be1d
commit
7a5733425e
25
src/Updux.ts
25
src/Updux.ts
@ -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
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
15
src/types.ts
15
src/types.ts
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user