From 21aeded2eaa0e597b70510a48cf8fd8c9f978476 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Tue, 25 May 2021 18:27:50 -0400 Subject: [PATCH] Update DispatchingStore to provide better typing for dispatch function parameters --- newstore/DispatchingStore.ts | 36 +++++++++++++++++++++--------------- newstore/history.ts | 17 ++++++++++------- newstore/settings.ts | 14 ++++++++------ 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/newstore/DispatchingStore.ts b/newstore/DispatchingStore.ts index e32b48f30..4406cdbc2 100644 --- a/newstore/DispatchingStore.ts +++ b/newstore/DispatchingStore.ts @@ -3,28 +3,37 @@ import { map } from "rxjs/operators" import assign from "lodash/assign" import clone from "lodash/clone" -export type Dispatchers = { - [key: string]: (currentVal: StoreType, payload: any) => Partial -} +type dispatcherFunc = ( + currentVal: StoreType, + payload: any +) => Partial + +/** + * Defines a dispatcher. + * + * This function exists to provide better typing for dispatch function. + * As you can see, its pretty much an identity function. + */ +export const defineDispatchers = ( + // eslint-disable-next-line no-unused-vars + dispatchers: { [_ in keyof T]: dispatcherFunc } +) => dispatchers type Dispatch< StoreType, - DispatchersType extends Dispatchers, - K extends keyof DispatchersType + DispatchersType extends Record> > = { - dispatcher: K & string + dispatcher: keyof DispatchersType payload: any } export default class DispatchingStore< StoreType, - DispatchersType extends Dispatchers + DispatchersType extends Record> > { #state$: BehaviorSubject - #dispatchers: Dispatchers - #dispatches$: Subject< - Dispatch - > = new Subject() + #dispatchers: DispatchersType + #dispatches$: Subject> = new Subject() constructor(initialValue: StoreType, dispatchers: DispatchersType) { this.#state$ = new BehaviorSubject(initialValue) @@ -56,10 +65,7 @@ export default class DispatchingStore< return this.#dispatches$ } - dispatch({ - dispatcher, - payload, - }: Dispatch) { + dispatch({ dispatcher, payload }: Dispatch) { if (!this.#dispatchers[dispatcher]) throw new Error(`Undefined dispatch type '${dispatcher}'`) diff --git a/newstore/history.ts b/newstore/history.ts index e88c02d83..3a9f5705a 100644 --- a/newstore/history.ts +++ b/newstore/history.ts @@ -1,6 +1,6 @@ import eq from "lodash/eq" import { pluck } from "rxjs/operators" -import DispatchingStore, { Dispatchers } from "./DispatchingStore" +import DispatchingStore, { defineDispatchers } from "./DispatchingStore" export const defaultRESTHistoryState = { state: [] as any[], @@ -15,18 +15,21 @@ export const HISTORY_LIMIT = 50 type RESTHistoryType = typeof defaultRESTHistoryState type GraphqlHistoryType = typeof defaultGraphqlHistoryState -const HistoryDispatcher: Dispatchers = { - setEntries(_, { entries }: { entries: any[] }) { +const HistoryDispatcher = defineDispatchers({ + setEntries( + _: RESTHistoryType | GraphqlHistoryType, + { entries }: { entries: any[] } + ) { return { state: entries, } }, - addEntry(currentVal, { entry }) { + addEntry(currentVal: RESTHistoryType | GraphqlHistoryType, { entry }) { return { state: [entry, ...currentVal.state].slice(0, HISTORY_LIMIT), } }, - deleteEntry(currentVal, { entry }) { + deleteEntry(currentVal: RESTHistoryType | GraphqlHistoryType, { entry }) { return { state: currentVal.state.filter((e) => !eq(e, entry)), } @@ -36,7 +39,7 @@ const HistoryDispatcher: Dispatchers = { state: [], } }, - toggleStar(currentVal, { entry }) { + toggleStar(currentVal: RESTHistoryType | GraphqlHistoryType, { entry }) { return { state: currentVal.state.map((e) => { if (eq(e, entry) && e.star !== undefined) { @@ -49,7 +52,7 @@ const HistoryDispatcher: Dispatchers = { }), } }, -} +}) export const restHistoryStore = new DispatchingStore( defaultRESTHistoryState, diff --git a/newstore/settings.ts b/newstore/settings.ts index cc92a3433..2b3536e53 100644 --- a/newstore/settings.ts +++ b/newstore/settings.ts @@ -1,8 +1,7 @@ import { pluck, distinctUntilChanged } from "rxjs/operators" import has from "lodash/has" import { Observable } from "rxjs" -import DispatchingStore from "./DispatchingStore" -import type { Dispatchers } from "./DispatchingStore" +import DispatchingStore, { defineDispatchers } from "./DispatchingStore" import type { KeysMatching } from "~/types/ts-utils" export const defaultSettings = { @@ -28,12 +27,15 @@ export type SettingsType = typeof defaultSettings const validKeys = Object.keys(defaultSettings) -const dispatchers: Dispatchers = { - bulkApplySettings(_currentState, payload: Partial) { +const dispatchers = defineDispatchers({ + bulkApplySettings( + _currentState: SettingsType, + payload: Partial + ) { return payload }, toggleSetting( - currentState, + currentState: SettingsType, { settingKey }: { settingKey: KeysMatching } ) { if (!has(currentState, settingKey)) { @@ -80,7 +82,7 @@ const dispatchers: Dispatchers = { return result }, -} +}) export const settingsStore = new DispatchingStore(defaultSettings, dispatchers)