Skip to content

Commit 07456db

Browse files
authored
Propagate store enhancer generic type when using composeWithDevTools (#1323)
* Propagate store enhancer generic type when using composeWithDevTools * Create silent-rats-tickle.md * Update silent-rats-tickle.md
1 parent c72c021 commit 07456db

File tree

3 files changed

+61
-14
lines changed

3 files changed

+61
-14
lines changed

.changeset/silent-rats-tickle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@redux-devtools/extension': patch
3+
---
4+
5+
Propagate store enhancer generic type when using composeWithDevTools

extension/src/pageScript/index.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -591,21 +591,38 @@ const preEnhancer =
591591
} as any;
592592
};
593593

594+
export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
595+
infer HeadStoreEnhancer,
596+
...infer RestStoreEnhancers
597+
]
598+
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
599+
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
600+
: never
601+
: unknown;
602+
594603
const extensionCompose =
595604
(config: Config) =>
596-
(...funcs: StoreEnhancer[]): StoreEnhancer => {
605+
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
606+
...funcs: StoreEnhancers
607+
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
608+
// @ts-ignore FIXME
597609
return (...args) => {
598610
const instanceId = generateId(config.instanceId);
599611
return [preEnhancer(instanceId), ...funcs].reduceRight(
612+
// @ts-ignore FIXME
600613
(composed, f) => f(composed),
601614
__REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args)
602615
);
603616
};
604617
};
605618

606619
interface ReduxDevtoolsExtensionCompose {
607-
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
608-
(...funcs: StoreEnhancer[]): StoreEnhancer;
620+
(config: Config): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
621+
...funcs: StoreEnhancers
622+
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
623+
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
624+
...funcs: StoreEnhancers
625+
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
609626
}
610627

611628
declare global {
@@ -616,18 +633,24 @@ declare global {
616633

617634
function reduxDevtoolsExtensionCompose(
618635
config: Config
619-
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
636+
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
637+
...funcs: StoreEnhancers
638+
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
639+
function reduxDevtoolsExtensionCompose<
640+
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
641+
>(
642+
...funcs: StoreEnhancers
643+
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
620644
function reduxDevtoolsExtensionCompose(
621-
...funcs: StoreEnhancer[]
622-
): StoreEnhancer;
623-
function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {
645+
...funcs: [Config] | StoreEnhancer<unknown>[]
646+
) {
624647
if (funcs.length === 0) {
625648
return __REDUX_DEVTOOLS_EXTENSION__();
626649
}
627650
if (funcs.length === 1 && typeof funcs[0] === 'object') {
628651
return extensionCompose(funcs[0]);
629652
}
630-
return extensionCompose({})(...(funcs as StoreEnhancer[]));
653+
return extensionCompose({})(...(funcs as StoreEnhancer<unknown>[]));
631654
}
632655

633656
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;

packages/redux-devtools-extension/src/index.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,22 @@ interface ReduxDevtoolsExtension {
227227
connect: (preConfig: Config) => ConnectResponse;
228228
}
229229

230+
export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
231+
infer HeadStoreEnhancer,
232+
...infer RestStoreEnhancers
233+
]
234+
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
235+
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
236+
: never
237+
: unknown;
238+
230239
export interface ReduxDevtoolsExtensionCompose {
231-
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
232-
(...funcs: StoreEnhancer[]): StoreEnhancer;
240+
(config: Config): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
241+
...funcs: StoreEnhancers
242+
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
243+
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
244+
...funcs: StoreEnhancers
245+
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
233246
}
234247

235248
declare global {
@@ -241,12 +254,18 @@ declare global {
241254

242255
function extensionComposeStub(
243256
config: Config
244-
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
245-
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
246-
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
257+
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
258+
...funcs: StoreEnhancers
259+
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
260+
function extensionComposeStub<
261+
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
262+
>(
263+
...funcs: StoreEnhancers
264+
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
265+
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
247266
if (funcs.length === 0) return undefined;
248267
if (typeof funcs[0] === 'object') return compose;
249-
return compose(...(funcs as StoreEnhancer[]));
268+
return compose(...(funcs as StoreEnhancer<unknown>[]));
250269
}
251270

252271
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =

0 commit comments

Comments
 (0)