Skip to content

Commit 8907715

Browse files
committed
Determine type of sidebar store automatically
Avoid the need to manually create the `SidebarStore` type by inferring it automatically. This works as follows: 1. The `modules` argument to `createStore` has been converted to a tuple type (`[ModuleA, ModuleB, ...]`) 2. The type of a module that would result from merging all the individual modules (`ModuleA & ModuleB ...`) is computed using a `TupleToIntersection` utility type 3. `StoreFromModule` is used to compute the type of the store that the merged module would produce
1 parent 9d40fff commit 8907715

2 files changed

Lines changed: 23 additions & 33 deletions

File tree

src/sidebar/store/create-store.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ import { createReducer, bindSelectors } from './util';
8383
* SelectorMethods<RootSelectors>} Store
8484
*/
8585

86+
/**
87+
* @template T
88+
* @typedef {{[K in keyof T]: (x: T[K]) => void }} MapContravariant
89+
*/
90+
91+
/**
92+
* Utility that turns a tuple type `[A, B, C]` into an intersection `A & B & C`.
93+
*
94+
* The implementation is magic adapted from https://github.com/microsoft/TypeScript/issues/28323.
95+
*
96+
* @template T
97+
* @template {Record<number, unknown>} [Temp=MapContravariant<T>]
98+
* @typedef {Temp[number] extends (x: infer U) => unknown ? U : never} TupleToIntersection
99+
*/
100+
86101
/**
87102
* Create a Redux store from a set of _modules_.
88103
*
@@ -107,10 +122,11 @@ import { createReducer, bindSelectors } from './util';
107122
* `use-store.js`. This returns a proxy which enables UI components to observe
108123
* what store state a component depends upon and re-render when it changes.
109124
*
110-
* @param {Module<any,any,any,any>[]} modules
125+
* @template {readonly Module<any,any,any,any>[]} Modules
126+
* @param {Modules} modules
111127
* @param {any[]} [initArgs] - Arguments to pass to each state module's `initialState` function
112128
* @param {any[]} [middleware] - List of additional Redux middlewares to use
113-
* @return Store<any,any,any>
129+
* @return {StoreFromModule<TupleToIntersection<Modules>>}
114130
*/
115131
export function createStore(modules, initArgs = [], middleware = []) {
116132
// Create the initial state and state update function.
@@ -174,7 +190,7 @@ export function createStore(modules, initArgs = [], middleware = []) {
174190

175191
Object.assign(store, boundActions, boundSelectors);
176192

177-
return store;
193+
return /** @type {any} */ (store);
178194
}
179195

180196
/**

src/sidebar/store/index.js

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,7 @@ import { sidebarPanelsModule } from './modules/sidebar-panels';
1717
import { toastMessagesModule } from './modules/toast-messages';
1818
import { viewerModule } from './modules/viewer';
1919

20-
/**
21-
* @template M
22-
* @typedef {import('./create-store').StoreFromModule<M>} StoreFromModule
23-
*/
24-
25-
/**
26-
* @typedef {StoreFromModule<activityModule> &
27-
* StoreFromModule<annotationsModule> &
28-
* StoreFromModule<defaultsModule> &
29-
* StoreFromModule<directLinkedModule> &
30-
* StoreFromModule<draftsModule> &
31-
* StoreFromModule<filtersModule> &
32-
* StoreFromModule<framesModule> &
33-
* StoreFromModule<groupsModule> &
34-
* StoreFromModule<linksModule> &
35-
* StoreFromModule<realTimeUpdatesModule> &
36-
* StoreFromModule<routeModule> &
37-
* StoreFromModule<selectionModule> &
38-
* StoreFromModule<sessionModule> &
39-
* StoreFromModule<sidebarPanelsModule> &
40-
* StoreFromModule<toastMessagesModule> &
41-
* StoreFromModule<viewerModule>
42-
* } SidebarStore
43-
*/
20+
/** @typedef {ReturnType<createSidebarStore>} SidebarStore */
4421

4522
/**
4623
* Create the central state store for the sidebar application.
@@ -52,13 +29,12 @@ import { viewerModule } from './modules/viewer';
5229
* [1] https://redux.js.org
5330
*
5431
* @param {import('../../types/config').SidebarSettings} settings
55-
* @return {SidebarStore}
5632
* @inject
5733
*/
5834
export function createSidebarStore(settings) {
5935
const middleware = [debugMiddleware];
6036

61-
const modules = [
37+
const modules = /** @type {const} */ ([
6238
activityModule,
6339
annotationsModule,
6440
defaultsModule,
@@ -75,8 +51,6 @@ export function createSidebarStore(settings) {
7551
sidebarPanelsModule,
7652
toastMessagesModule,
7753
viewerModule,
78-
];
79-
return /** @type {SidebarStore} */ (
80-
createStore(modules, [settings], middleware)
81-
);
54+
]);
55+
return createStore(modules, [settings], middleware);
8256
}

0 commit comments

Comments
 (0)