I am trying to set up state in a monorepo application by composing reducers. Currently, all state is divided by domain, e.g.

type State = { fruit: FruitState, snacks: SnackState })

Each state domain contains some selectors. These selectors are defined in an encapsulated manner, e.g.

const selectApples = (state: FruitState) => state.apples;

We then have a web module which imports all the state domain selectors, grouping them by key and then wrapping them in a higher-order function to scope them into domain namespaces, e.g.

function scopeSelector<T extends keyof State>( scopeNamespace: T, selectors: { [selector: string]: Function } ) { return Object.keys(selectors).reduce((scoped, key) => ({ ...scoped, [key]: (state: State) => selectors[key](state[scopeNamespace]) }), {}); } export const selectors = { fruits: scopeSelector('fruits', fruits.selectors), snacks: scopeSelector('snacks', snacks.selectors) };

This code works at runtime - but produces TypeScript errors, e.g.

// Error: Property 'selectApples' does not exist on type '{}'. const apples = selectors.fruits.selectApples(state);

I have tried using Ramda's map with the advanced typings from npm-ramda. This nearly worked, except the return result of any selector was a union of all selectors within its "scope".

I have set up a project on StackBlitz which demonstrates the problem.