diff --git a/.changeset/silent-rats-tickle.md b/.changeset/silent-rats-tickle.md new file mode 100644 index 00000000..8ae0547d --- /dev/null +++ b/.changeset/silent-rats-tickle.md @@ -0,0 +1,5 @@ +--- +'@redux-devtools/extension': patch +--- + +Propagate store enhancer generic type when using composeWithDevTools diff --git a/extension/src/pageScript/index.ts b/extension/src/pageScript/index.ts index 4b6bfb35..fef17af1 100644 --- a/extension/src/pageScript/index.ts +++ b/extension/src/pageScript/index.ts @@ -591,12 +591,25 @@ const preEnhancer = } as any; }; +export type InferComposedStoreExt = StoreEnhancers extends [ + infer HeadStoreEnhancer, + ...infer RestStoreEnhancers +] + ? HeadStoreEnhancer extends StoreEnhancer + ? StoreExt & InferComposedStoreExt + : never + : unknown; + const extensionCompose = (config: Config) => - (...funcs: StoreEnhancer[]): StoreEnhancer => { + []>( + ...funcs: StoreEnhancers + ): StoreEnhancer> => { + // @ts-ignore FIXME return (...args) => { const instanceId = generateId(config.instanceId); return [preEnhancer(instanceId), ...funcs].reduceRight( + // @ts-ignore FIXME (composed, f) => f(composed), __REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args) ); @@ -604,8 +617,12 @@ const extensionCompose = }; interface ReduxDevtoolsExtensionCompose { - (config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer; - (...funcs: StoreEnhancer[]): StoreEnhancer; + (config: Config): []>( + ...funcs: StoreEnhancers + ) => StoreEnhancer>; + []>( + ...funcs: StoreEnhancers + ): StoreEnhancer>; } declare global { @@ -616,18 +633,24 @@ declare global { function reduxDevtoolsExtensionCompose( config: Config -): (...funcs: StoreEnhancer[]) => StoreEnhancer; +): []>( + ...funcs: StoreEnhancers +) => StoreEnhancer>; +function reduxDevtoolsExtensionCompose< + StoreEnhancers extends readonly StoreEnhancer[] +>( + ...funcs: StoreEnhancers +): StoreEnhancer>; function reduxDevtoolsExtensionCompose( - ...funcs: StoreEnhancer[] -): StoreEnhancer; -function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) { + ...funcs: [Config] | StoreEnhancer[] +) { if (funcs.length === 0) { return __REDUX_DEVTOOLS_EXTENSION__(); } if (funcs.length === 1 && typeof funcs[0] === 'object') { return extensionCompose(funcs[0]); } - return extensionCompose({})(...(funcs as StoreEnhancer[])); + return extensionCompose({})(...(funcs as StoreEnhancer[])); } window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose; diff --git a/packages/redux-devtools-extension/src/index.ts b/packages/redux-devtools-extension/src/index.ts index 54ba0545..2186f1ab 100644 --- a/packages/redux-devtools-extension/src/index.ts +++ b/packages/redux-devtools-extension/src/index.ts @@ -227,9 +227,22 @@ interface ReduxDevtoolsExtension { connect: (preConfig: Config) => ConnectResponse; } +export type InferComposedStoreExt = StoreEnhancers extends [ + infer HeadStoreEnhancer, + ...infer RestStoreEnhancers +] + ? HeadStoreEnhancer extends StoreEnhancer + ? StoreExt & InferComposedStoreExt + : never + : unknown; + export interface ReduxDevtoolsExtensionCompose { - (config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer; - (...funcs: StoreEnhancer[]): StoreEnhancer; + (config: Config): []>( + ...funcs: StoreEnhancers + ) => StoreEnhancer>; + []>( + ...funcs: StoreEnhancers + ): StoreEnhancer>; } declare global { @@ -241,12 +254,18 @@ declare global { function extensionComposeStub( config: Config -): (...funcs: StoreEnhancer[]) => StoreEnhancer; -function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer; -function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) { +): []>( + ...funcs: StoreEnhancers +) => StoreEnhancer>; +function extensionComposeStub< + StoreEnhancers extends readonly StoreEnhancer[] +>( + ...funcs: StoreEnhancers +): StoreEnhancer>; +function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) { if (funcs.length === 0) return undefined; if (typeof funcs[0] === 'object') return compose; - return compose(...(funcs as StoreEnhancer[])); + return compose(...(funcs as StoreEnhancer[])); } export const composeWithDevTools: ReduxDevtoolsExtensionCompose =