diff --git a/extension/src/app/api/index.ts b/extension/src/app/api/index.ts index aeda37dc..e5c27c08 100644 --- a/extension/src/app/api/index.ts +++ b/extension/src/app/api/index.ts @@ -8,11 +8,7 @@ import importState from './importState'; import generateId from './generateInstanceId'; import { Config } from '../../browser/extension/inject/pageScript'; import { Action } from 'redux'; -import { - EnhancedStore, - LiftedState, - PerformAction, -} from '@redux-devtools/instrument'; +import { LiftedState, PerformAction } from '@redux-devtools/instrument'; import { LibConfig } from '@redux-devtools/app/lib/actions'; import { ContentScriptToPageScriptMessage, @@ -527,7 +523,7 @@ export function disconnect() { export interface ConnectResponse { init: >( state: S, - liftedData: LiftedState + liftedData?: LiftedState ) => void; subscribe: >( listener: (message: ListenerMessage) => void @@ -650,7 +646,7 @@ export function connect(preConfig: Config): ConnectResponse { const init = >( state: S, - liftedData: LiftedState + liftedData?: LiftedState ) => { const message: InitMessage = { type: 'INIT', diff --git a/extension/src/browser/extension/inject/pageScript.ts b/extension/src/browser/extension/inject/pageScript.ts index b23fa46d..74728611 100644 --- a/extension/src/browser/extension/inject/pageScript.ts +++ b/extension/src/browser/extension/inject/pageScript.ts @@ -585,30 +585,41 @@ const preEnhancer = const extensionCompose = (config: Config) => - (...funcs: StoreEnhancer[]) => { - return (...args: any[]) => { + (...funcs: StoreEnhancer[]): StoreEnhancer => { + return (...args) => { const instanceId = generateId(config.instanceId); return [preEnhancer(instanceId), ...funcs].reduceRight( (composed, f) => f(composed), - (__REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId }) as any)( - ...args - ) + __REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args) ); }; }; +interface ReduxDevtoolsExtensionCompose { + (config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer; + (...funcs: StoreEnhancer[]): StoreEnhancer; +} + declare global { interface Window { - __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: unknown; + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: ReduxDevtoolsExtensionCompose; } } -window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = (...funcs: any[]) => { +function reduxDevtoolsExtensionCompose( + config: Config +): (...funcs: StoreEnhancer[]) => StoreEnhancer; +function reduxDevtoolsExtensionCompose( + ...funcs: StoreEnhancer[] +): StoreEnhancer; +function reduxDevtoolsExtensionCompose(...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); -}; + return extensionCompose({})(...(funcs as StoreEnhancer[])); +} + +window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose; diff --git a/packages/redux-devtools-extension/src/developmentOnly.ts b/packages/redux-devtools-extension/src/developmentOnly.ts index 45454aba..97b4deb4 100644 --- a/packages/redux-devtools-extension/src/developmentOnly.ts +++ b/packages/redux-devtools-extension/src/developmentOnly.ts @@ -1,18 +1,28 @@ import { compose, StoreEnhancer } from 'redux'; -import { EnhancerOptions } from './index'; +import { Config, EnhancerOptions } from './index'; -declare const process: any; +declare const process: { + env: { + NODE_ENV: string; + }; +}; + +function extensionComposeStub( + config: Config +): (...funcs: StoreEnhancer[]) => StoreEnhancer; +function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer; +function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) { + if (funcs.length === 0) return undefined; + if (typeof funcs[0] === 'object') return compose; + return compose(...(funcs as StoreEnhancer[])); +} export const composeWithDevTools = process.env.NODE_ENV !== 'production' && typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - : function () { - if (arguments.length === 0) return undefined; - if (typeof arguments[0] === 'object') return compose; - return compose.apply(null, arguments); - }; + : extensionComposeStub; export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = process.env.NODE_ENV !== 'production' && diff --git a/packages/redux-devtools-extension/src/index.ts b/packages/redux-devtools-extension/src/index.ts index 59f958c0..18eb4624 100644 --- a/packages/redux-devtools-extension/src/index.ts +++ b/packages/redux-devtools-extension/src/index.ts @@ -180,20 +180,46 @@ export interface EnhancerOptions { traceLimit?: number; } +export interface Config extends EnhancerOptions { + type?: string; +} + +interface ConnectResponse { + init: (state: unknown) => void; + send: (action: Action, state: unknown) => void; +} + +interface ReduxDevtoolsExtension { + (config?: Config): StoreEnhancer; + connect: (preConfig: Config) => ConnectResponse; +} + +export interface ReduxDevtoolsExtensionCompose { + (config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer; + (...funcs: StoreEnhancer[]): StoreEnhancer; +} + declare global { interface Window { - __REDUX_DEVTOOLS_EXTENSION__?: (options?: EnhancerOptions) => StoreEnhancer; + __REDUX_DEVTOOLS_EXTENSION__?: ReduxDevtoolsExtension; + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: ReduxDevtoolsExtensionCompose; } } -export const composeWithDevTools = +function extensionComposeStub( + config: Config +): (...funcs: StoreEnhancer[]) => StoreEnhancer; +function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer; +function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) { + if (funcs.length === 0) return undefined; + if (typeof funcs[0] === 'object') return compose; + return compose(...(funcs as StoreEnhancer[])); +} + +export const composeWithDevTools: ReduxDevtoolsExtensionCompose = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - : function () { - if (arguments.length === 0) return undefined; - if (typeof arguments[0] === 'object') return compose; - return compose.apply(null, arguments); - }; + : extensionComposeStub; export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ diff --git a/packages/redux-devtools-extension/src/logOnly.ts b/packages/redux-devtools-extension/src/logOnly.ts index c39ecb59..9528bafb 100644 --- a/packages/redux-devtools-extension/src/logOnly.ts +++ b/packages/redux-devtools-extension/src/logOnly.ts @@ -1,23 +1,33 @@ import assign from './utils/assign'; -import { compose, StoreEnhancer } from 'redux'; -import { EnhancerOptions } from './index'; +import { + Action, + compose, + Dispatch, + PreloadedState, + Reducer, + StoreEnhancer, +} from 'redux'; +import { Config, EnhancerOptions } from './index'; -function enhancer() { - const config = arguments[0] || {}; +function enhancer(options?: EnhancerOptions): StoreEnhancer { + const config: Config = options || {}; config.features = { pause: true, export: true, test: true }; config.type = 'redux'; if (config.autoPause === undefined) config.autoPause = true; if (config.latency === undefined) config.latency = 500; return function (createStore) { - return function (reducer, preloadedState, enhancer) { - const store = createStore(reducer, preloadedState, enhancer); + return function >( + reducer: Reducer, + preloadedState: PreloadedState | undefined + ) { + const store = createStore(reducer, preloadedState); const origDispatch = store.dispatch; - const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(config); + const devTools = window.__REDUX_DEVTOOLS_EXTENSION__!.connect(config); devTools.init(store.getState()); - const dispatch = function (action) { + const dispatch: Dispatch = function (action) { const r = origDispatch(action); devTools.send(action, store.getState()); return r; @@ -29,24 +39,27 @@ function enhancer() { }; } -function composeWithEnhancer(config) { - return function () { - return compose(compose.apply(null, arguments), enhancer(config)); +function composeWithEnhancer(config?: EnhancerOptions) { + return function (...funcs: StoreEnhancer[]) { + return compose(compose(...funcs), enhancer(config)); }; } -export const composeWithDevTools = function () { +export function composeWithDevTools( + config: Config +): (...funcs: StoreEnhancer[]) => StoreEnhancer; +export function composeWithDevTools(...funcs: StoreEnhancer[]): StoreEnhancer; +export function composeWithDevTools(...funcs: [Config] | StoreEnhancer[]) { if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) { - if (arguments.length === 0) return enhancer(); - if (typeof arguments[0] === 'object') - return composeWithEnhancer(arguments[0]); - return composeWithEnhancer().apply(null, arguments); + if (funcs.length === 0) return enhancer(); + if (typeof funcs[0] === 'object') return composeWithEnhancer(funcs[0]); + return composeWithEnhancer()(...(funcs as StoreEnhancer[])); } - if (arguments.length === 0) return undefined; - if (typeof arguments[0] === 'object') return compose; - return compose.apply(null, arguments); -}; + if (funcs.length === 0) return undefined; + if (typeof funcs[0] === 'object') return compose; + return compose(...(funcs as StoreEnhancer[])); +} export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ diff --git a/packages/redux-devtools-extension/src/logOnlyInProduction.ts b/packages/redux-devtools-extension/src/logOnlyInProduction.ts index bb8027ea..68d9fb60 100644 --- a/packages/redux-devtools-extension/src/logOnlyInProduction.ts +++ b/packages/redux-devtools-extension/src/logOnlyInProduction.ts @@ -1,8 +1,22 @@ import { compose, StoreEnhancer } from 'redux'; import * as logOnly from './logOnly'; -import { EnhancerOptions } from './index'; +import { Config, EnhancerOptions } from './index'; -declare const process: any; +declare const process: { + env: { + NODE_ENV: string; + }; +}; + +function extensionComposeStub( + config: Config +): (...funcs: StoreEnhancer[]) => StoreEnhancer; +function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer; +function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) { + if (funcs.length === 0) return undefined; + if (typeof funcs[0] === 'object') return compose; + return compose(...(funcs as StoreEnhancer[])); +} export const composeWithDevTools = process.env.NODE_ENV === 'production' @@ -10,11 +24,7 @@ export const composeWithDevTools = : typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ - : function () { - if (arguments.length === 0) return undefined; - if (typeof arguments[0] === 'object') return compose; - return compose.apply(null, arguments); - }; + : extensionComposeStub; export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = process.env.NODE_ENV === 'production' diff --git a/packages/redux-devtools-extension/src/utils/assign.ts b/packages/redux-devtools-extension/src/utils/assign.ts index 1b4f589a..b9588369 100644 --- a/packages/redux-devtools-extension/src/utils/assign.ts +++ b/packages/redux-devtools-extension/src/utils/assign.ts @@ -8,13 +8,17 @@ const objectKeys = return keys; }; -export default function assign(obj: {}, newKey, newValue) { +export default function assign( + obj: T, + newKey: K, + newValue: T[K] +): T { const keys = objectKeys(obj); - const copy = {}; + const copy: T = {} as T; for (let i = 0, l = keys.length; i < l; i++) { const key = keys[i]; - copy[key] = obj[key]; + copy[key as keyof T] = obj[key as keyof T]; } copy[newKey] = newValue; diff --git a/yarn.lock b/yarn.lock index 6442ada4..9def4ba1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4790,6 +4790,7 @@ __metadata: "@babel/preset-typescript": ^7.16.0 "@typescript-eslint/eslint-plugin": ^5.2.0 "@typescript-eslint/parser": ^5.2.0 + core-js: ^3.19.1 eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 redux: ^4.1.2 @@ -11732,6 +11733,13 @@ __metadata: languageName: node linkType: hard +"core-js@npm:^3.19.1": + version: 3.19.1 + resolution: "core-js@npm:3.19.1" + checksum: 2f669061788dc6fea823f0433d871deeaaaacc7d68ef2748859509522a34df5c83e648c3c6a1993fed0ab188081b3cf32b957b2a1f46156a2b20bd775961ade4 + languageName: node + linkType: hard + "core-util-is@npm:1.0.2": version: 1.0.2 resolution: "core-util-is@npm:1.0.2"