@rematch/select
Version:
Selectors plugin for Rematch
256 lines (236 loc) • 7.06 kB
text/typescript
// Type definitions for @rematch/select 2.0.0
// Definitions by: Sam Richard <https://github.com/d3dc>
import {
ExtractRematchStateFromModels,
Models,
Model,
Action,
RematchRootState,
ModelReducers,
ModelEffects,
ModelEffectsCreator,
} from '/core'
import * as Reselect from 'reselect'
import { Store as ReduxStore, Reducer as ReduxReducer } from 'redux'
export { createSelector, createStructuredSelector } from 'reselect'
export type Selector<TState, TReturns, TProps = void> = TProps extends void
? (state: TState) => TReturns
: (state: TState, props: TProps) => TReturns
export type ExtractSelectorsFromModel<
TModels extends Models<TModels>,
TModel extends Model<TModels>
> =
// thunk case: (models) => ({...})
TModel['selectors'] extends (...args: any[]) => infer TReturnObj
? TReturnObj
: // normal object case
TModel['selectors'] extends Record<string, any>
? TModel['selectors']
: never
export type ExtractSelectorsSignatureFromSelectorsModel<
TRootState,
TSelectorsConfigObject,
TKey extends keyof TSelectorsConfigObject
> = TSelectorsConfigObject[TKey] extends (...args: any[]) => infer TSelector
? // hasProps case
TSelector extends (props: infer TProps) => Selector<any, infer TReturns>
? (props: TProps) => Selector<TRootState, TReturns>
: // selector without props case
TSelector extends Selector<any, infer TReturns>
? Selector<TRootState, TReturns>
: // selector with props case
TSelector extends Selector<any, infer TReturns, infer TProps>
? Selector<TRootState, TReturns, TProps>
: never
: never
export interface SelectConfig<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>
> {
sliceState?: (
state: ExtractRematchStateFromModels<TModels, TExtraModels>,
model: Model<TModels>
) => Record<string, any> | undefined
selectorCreator?: any
}
export type ModelSelectors<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TModel extends Model<TModels>
> = {
[key in keyof ExtractSelectorsFromModel<
TModels,
TModel
>]: ExtractSelectorsSignatureFromSelectorsModel<
RematchRootState<TModels, TExtraModels>,
ExtractSelectorsFromModel<TModels, TModel>,
key
>
}
export type Slicer<TSliceState, TRootState> = (<TReturns>(
resultFn: (slice: TSliceState) => TReturns
) => Selector<TRootState, TReturns>) &
Selector<TRootState, TSliceState>
export interface ModelSelectorFactories<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any
> {
[key: string]:
| SelectorFactory<TModels, TExtraModels, TSliceState>
| SelectorParametricFactory<TModels, TExtraModels, TSliceState>
}
export type StoreSelectors<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>
> = {
[TModelKey in keyof TModels]: ModelSelectors<
TModels,
TExtraModels,
TModels[TModelKey]
>
}
export type SelectorFactory<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any
> = <TReturns>(
// FIXME: https://github.com/Microsoft/TypeScript/issues/27862
this: ModelSelectorFactories<TModels, TExtraModels, TSliceState>,
models: StoreSelectors<TModels, TExtraModels>
) => Selector<RematchRootState<TModels>, TReturns>
export type SelectorParametricFactory<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any,
TProps = any,
TReturns = any
> = (
// FIXME: https://github.com/Microsoft/TypeScript/issues/27862
this: ModelSelectorFactories<TModels, TExtraModels, TSliceState>,
models: StoreSelectors<TModels, TExtraModels>,
props: TProps
) => Selector<RematchRootState<TModels>, TReturns, TProps>
// the same as `SelectorParametricFactory` but with different return signature
export type ParameterizerSelectorFactory<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any,
TProps = any,
TReturns = any
> = (
// FIXME: https://github.com/Microsoft/TypeScript/issues/27862
this: ModelSelectorFactories<TModels, TExtraModels, TSliceState>,
models: StoreSelectors<TModels, TExtraModels>,
props: TProps
) => (props: TProps) => Selector<RematchRootState<TModels>, TReturns>
export type Parameterizer<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any
> = <TProps, TReturns>(
factory: SelectorParametricFactory<
TModels,
TExtraModels,
TSliceState,
TProps,
TReturns
>
) => ParameterizerSelectorFactory<
TModels,
TExtraModels,
TSliceState,
TProps,
TReturns
>
export type ModelSelectorsFactory<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TSliceState = any
> = (
slice: Slicer<TSliceState, RematchRootState<TModels>>,
createSelector: typeof Reselect.createSelector,
hasProps: Parameterizer<TModels, TExtraModels, TSliceState>
) => ModelSelectorFactories<TModels, TExtraModels, TSliceState>
export type ModelSelectorsConfig<
TModels extends Models<TModels>,
TSliceState = any,
TExtraModels extends Models<TModels> = Record<string, never>
> =
| ModelSelectorsFactory<TModels, TExtraModels, TSliceState>
| ModelSelectorFactories<TModels, TExtraModels, TSliceState>
export type RematchSelect<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>,
TRootState = RematchRootState<TModels, TExtraModels>
> = (<TReturn extends { [key: string]: (state: TRootState) => any }>(
mapSelectToProps: (select: RematchSelect<TModels, TExtraModels>) => TReturn
) => Reselect.OutputParametricSelector<
TRootState,
any,
{ [K in keyof TReturn]: ReturnType<TReturn[K]> },
Reselect.Selector<TRootState, TRootState>
> &
Reselect.OutputSelector<
TRootState,
{ [K in keyof TReturn]: ReturnType<TReturn[K]> },
Reselect.Selector<TRootState, TRootState>
>) &
StoreSelectors<TModels, TExtraModels>
declare module '/core' {
// Add overloads for store to add select
interface RematchStore<
TModels extends Models<TModels>,
TExtraModels extends Models<TModels>
> extends ReduxStore<RematchRootState<TModels, TExtraModels>, Action> {
select: RematchSelect<
TModels,
TExtraModels,
RematchRootState<TModels, TExtraModels>
>
}
// add overloads for Model here.
interface Model<TModels extends Models<TModels>, TState = any> {
selectors?: ModelSelectorsConfig<TModels, TState>
}
// add overloads for ModelCreator here.
interface ModelCreator {
<RM extends Models<RM>>(): <
R extends ModelReducers<S> | undefined,
BR extends ReduxReducer<BS> | undefined,
E extends ModelEffects<RM> | ModelEffectsCreator<RM> | undefined,
SE extends ModelSelectorsConfig<RM, S> | undefined,
S,
BS = S
>(mo: {
name?: string
state: S
reducers?: R
baseReducer?: BR
effects?: E
selectors?: SE
}) => {
name?: string
state: S
} & (E extends undefined
? {}
: {
effects: E
}) &
(R extends undefined
? {}
: {
reducers: R
}) &
(BR extends undefined
? {}
: {
baseReducer: BR
}) &
(SE extends undefined
? {}
: {
selectors: SE
})
}
}