diff --git a/packages/redux-devtools-core/src/app/actions/index.ts b/packages/redux-devtools-core/src/app/actions/index.ts index 05546088..ac79a39a 100644 --- a/packages/redux-devtools-core/src/app/actions/index.ts +++ b/packages/redux-devtools-core/src/app/actions/index.ts @@ -20,6 +20,9 @@ import { UPDATE_REPORTS, REMOVE_INSTANCE, SET_STATE, + GET_REPORT_ERROR, + GET_REPORT_SUCCESS, + ERROR, } from '../constants/actionTypes'; import { AUTH_ERROR, @@ -41,6 +44,7 @@ import { Action } from 'redux'; import { Features, State } from '../reducers/instances'; import { MonitorStateMonitorState } from '../reducers/monitor'; import { LiftedAction } from 'redux-devtools-instrument'; +import { Data } from '../reducers/reports'; let monitorReducer: ( monitorProps: unknown, @@ -95,49 +99,73 @@ export interface MonitorActionAction { ) => unknown; monitorProps: unknown; } -interface JumpToStateAction { +export interface JumpToStateAction { type: 'JUMP_TO_STATE'; index: number; actionId: number; } -interface JumpToActionAction { +export interface JumpToActionAction { type: 'JUMP_TO_ACTION'; index: number; actionId: number; } -interface PauseRecordingAction { +export interface PauseRecordingAction { type: 'PAUSE_RECORDING'; status: boolean; } -interface LockChangesAction { +export interface LockChangesAction { type: 'LOCK_CHANGES'; status: boolean; } -export interface LiftedActionDispatchAction { - type: typeof LIFTED_ACTION; - message: 'DISPATCH'; - action: - | JumpToStateAction - | JumpToActionAction - | PauseRecordingAction - | LockChangesAction; +export interface ToggleActionAction { + type: 'TOGGLE_ACTION'; +} +export interface RollbackAction { + type: 'ROLLBACK'; +} +export interface SweepAction { + type: 'SWEEP'; +} +export type DispatchAction = + | JumpToStateAction + | JumpToActionAction + | PauseRecordingAction + | LockChangesAction + | ToggleActionAction + | RollbackAction + | SweepAction; +interface LiftedActionActionBase { + action?: DispatchAction | string | CustomAction; + state?: string; toAll?: boolean; } -interface LiftedActionImportAction { +export interface LiftedActionDispatchAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'DISPATCH'; + action: DispatchAction; + toAll?: boolean; +} +interface LiftedActionImportAction extends LiftedActionActionBase { type: typeof LIFTED_ACTION; message: 'IMPORT'; state: string; preloadedState: unknown | undefined; } -interface LiftedActionActionAction { +interface LiftedActionActionAction extends LiftedActionActionBase { type: typeof LIFTED_ACTION; message: 'ACTION'; - action: Action; + action: string | CustomAction; +} +interface LiftedActionExportAction extends LiftedActionActionBase { + type: typeof LIFTED_ACTION; + message: 'EXPORT'; + toExport: boolean; } export type LiftedActionAction = | LiftedActionDispatchAction | LiftedActionImportAction - | LiftedActionActionAction; + | LiftedActionActionAction + | LiftedActionExportAction; export function liftedDispatch( action: | InitMonitorAction @@ -237,8 +265,14 @@ export function pauseRecording(status: boolean): LiftedActionDispatchAction { }; } +export interface CustomAction { + name: string; + selected: number; + args: (string | undefined)[]; + rest: string; +} export function dispatchRemotely( - action: Action + action: string | CustomAction ): LiftedActionActionAction { return { type: LIFTED_ACTION, message: 'ACTION', action }; } @@ -317,6 +351,7 @@ export function getReport(report: unknown): GetReportRequest { export interface ActionCreator { args: string[]; + name: string; } interface LibConfig { @@ -337,6 +372,7 @@ export interface RequestBase { computedStates?: string; // eslint-disable-next-line @typescript-eslint/ban-types payload?: {} | string; + liftedState?: Partial; } interface InitRequest extends RequestBase { type: 'INIT'; @@ -344,6 +380,10 @@ interface InitRequest extends RequestBase { } interface ActionRequest extends RequestBase { type: 'ACTION'; + isExcess: boolean; + nextActionId: number; + maxAge: number; + batched: boolean; } interface StateRequest extends RequestBase { type: 'STATE'; @@ -352,16 +392,22 @@ interface StateRequest extends RequestBase { interface PartialStateRequest extends RequestBase { type: 'PARTIAL_STATE'; committedState: unknown; + maxAge: number; } interface LiftedRequest extends RequestBase { type: 'LIFTED'; } +export interface ExportRequest extends RequestBase { + type: 'EXPORT'; + committedState: unknown; +} export type Request = | InitRequest | ActionRequest | StateRequest | PartialStateRequest - | LiftedRequest; + | LiftedRequest + | ExportRequest; interface UpdateStateAction { type: typeof UPDATE_STATE; @@ -445,10 +491,47 @@ interface UnsubscribeAction { channel: string; } -interface EmitAction { +export interface EmitAction { type: typeof EMIT; message: string; - id: string; + id?: string | false; + instanceId?: string; + action?: unknown; + state?: unknown; +} + +interface ListRequest { + type: 'list'; + data: Data; +} +interface AddRequest { + type: 'add'; + data: Data; +} +interface RemoveRequest { + type: 'remove'; + data: Data; + id: unknown; +} +type UpdateReportsRequest = ListRequest | AddRequest | RemoveRequest; +interface UpdateReportsAction { + type: typeof UPDATE_REPORTS; + request: UpdateReportsRequest; +} + +interface GetReportError { + type: typeof GET_REPORT_ERROR; + error: Error; +} + +interface GetReportSuccess { + type: typeof GET_REPORT_SUCCESS; + data: { payload: string }; +} + +interface ErrorAction { + type: typeof ERROR; + payload: string; } export type StoreAction = @@ -483,4 +566,8 @@ export type StoreAction = | SubscribeSuccessAction | SubscribeErrorAction | UnsubscribeAction - | EmitAction; + | EmitAction + | UpdateReportsAction + | GetReportError + | GetReportSuccess + | ErrorAction; diff --git a/packages/redux-devtools-core/src/app/components/Settings/index.tsx b/packages/redux-devtools-core/src/app/components/Settings/index.tsx index f50e95df..ff562ae2 100644 --- a/packages/redux-devtools-core/src/app/components/Settings/index.tsx +++ b/packages/redux-devtools-core/src/app/components/Settings/index.tsx @@ -21,7 +21,8 @@ class Settings extends Component<{}, State> { render() { return ( - toRight tabs={this.tabs} selected={this.state.selected} diff --git a/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts b/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts index 95e00b6a..825dbb77 100644 --- a/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts +++ b/packages/redux-devtools-core/src/app/constants/socketActionTypes.ts @@ -1,5 +1,14 @@ import socketCluster from 'socketcluster-client'; +interface States { + CLOSED: 'closed'; + CONNECTING: 'connecting'; + OPEN: 'open'; + AUTHENTICATED: 'authenticated'; + PENDING: 'pending'; + UNAUTHENTICATED: 'unauthenticated'; +} + export const { CLOSED, CONNECTING, @@ -7,7 +16,7 @@ export const { AUTHENTICATED, PENDING, UNAUTHENTICATED, -} = socketCluster.SCClientSocket; +} = (socketCluster.SCClientSocket as unknown) as States; export const CONNECT_REQUEST = 'socket/CONNECT_REQUEST'; export const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS'; export const CONNECT_ERROR = 'socket/CONNECT_ERROR'; diff --git a/packages/redux-devtools-core/src/app/containers/Actions.tsx b/packages/redux-devtools-core/src/app/containers/Actions.tsx index 494adfa3..d813203c 100644 --- a/packages/redux-devtools-core/src/app/containers/Actions.tsx +++ b/packages/redux-devtools-core/src/app/containers/Actions.tsx @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { connect, ResolveThunks } from 'react-redux'; import { Container } from 'devui'; import SliderMonitor from './monitors/Slider'; @@ -55,16 +54,6 @@ class Actions extends Component { } } -Actions.propTypes = { - liftedDispatch: PropTypes.func.isRequired, - liftedState: PropTypes.object.isRequired, - monitorState: PropTypes.object, - options: PropTypes.object.isRequired, - monitor: PropTypes.string, - dispatcherIsOpen: PropTypes.bool, - sliderIsOpen: PropTypes.bool, -}; - const mapStateToProps = (state: StoreState) => { const instances = state.instances; const id = getActiveInstance(instances); diff --git a/packages/redux-devtools-core/src/app/containers/DevTools.tsx b/packages/redux-devtools-core/src/app/containers/DevTools.tsx index dad48085..cbfff2de 100644 --- a/packages/redux-devtools-core/src/app/containers/DevTools.tsx +++ b/packages/redux-devtools-core/src/app/containers/DevTools.tsx @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import { withTheme } from 'styled-components'; import { LiftedAction, LiftedState } from 'redux-devtools-instrument'; import { Action } from 'redux'; -import { Monitor } from 'redux-devtools'; import getMonitor from '../utils/getMonitor'; import { InitMonitorAction } from '../actions'; import { Features, State } from '../reducers/instances'; @@ -22,13 +21,15 @@ interface Props { class DevTools extends Component { monitorProps: unknown; - Monitor?: Monitor< - unknown, - Action, - LiftedState, unknown>, - unknown, - Action - >; + Monitor?: React.ComponentType< + LiftedState, unknown> + > & { + update( + monitorProps: unknown, + state: unknown | undefined, + action: Action + ): unknown; + }; preventRender?: boolean; constructor(props: Props) { @@ -41,6 +42,7 @@ class DevTools extends Component { this.monitorProps = monitorElement.props; this.Monitor = monitorElement.type; + // eslint-disable-next-line @typescript-eslint/unbound-method const update = this.Monitor!.update; if (update) { let newMonitorState; @@ -51,7 +53,11 @@ class DevTools extends Component { ) { newMonitorState = monitorState; } else { - newMonitorState = update(this.monitorProps, undefined, {}); + newMonitorState = update( + this.monitorProps, + undefined, + {} as Action + ); if (newMonitorState !== monitorState) { this.preventRender = true; } @@ -95,9 +101,10 @@ class DevTools extends Component { ...this.props.liftedState, monitorState: this.props.monitorState, }; + const MonitorAsAny = this.Monitor as any; return (
- { render() { return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore { - state = { + state: State = { selected: 'default', customAction: this.props.options.lib === 'redux' ? "{\n type: ''\n}" : 'this.', @@ -89,7 +89,7 @@ class Dispatcher extends Component { ); } - selectActionCreator = (selected) => { + selectActionCreator = (selected: 'default' | 'actions-help' | number) => { if (selected === 'actions-help') { window.open( 'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/' + @@ -98,14 +98,14 @@ class Dispatcher extends Component { return; } - const args = []; + const args: string[] = []; if (selected !== 'default') { args.length = this.props.options.actionCreators![selected].args.length; } this.setState({ selected, args, rest: '[]', changed: false }); }; - handleArg = (argIndex) => (value) => { + handleArg = (argIndex: number) => (value: string) => { const args = [ ...this.state.args.slice(0, argIndex), value || undefined, @@ -114,26 +114,26 @@ class Dispatcher extends Component { this.setState({ args, changed: true }); }; - handleRest = (rest) => { + handleRest = (rest: string) => { this.setState({ rest, changed: true }); }; - handleCustomAction = (customAction) => { + handleCustomAction = (customAction: string) => { this.setState({ customAction, changed: true }); }; dispatchAction = () => { const { selected, customAction, args, rest } = this.state; - if (this.state.selected !== 'default') { + if (selected !== 'default') { // remove trailing `undefined` arguments let i = args.length - 1; while (i >= 0 && typeof args[i] === 'undefined') { - args.pop(i); + args.pop(); i--; } this.props.dispatch({ - name: this.props.options.actionCreators[selected].name, + name: this.props.options.actionCreators![selected].name, selected, args, rest, @@ -182,7 +182,9 @@ class Dispatcher extends Component { ); } - let options = [{ value: 'default', label: 'Custom action' }]; + let options: { value: string | number; label: string }[] = [ + { value: 'default', label: 'Custom action' }, + ]; if (actionCreators && actionCreators.length > 0) { options = options.concat( actionCreators.map(({ name, args }, i) => ({ diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx index ff6e3875..f2fc0b60 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/ChartTab.tsx @@ -72,20 +72,20 @@ class ChartTab extends Component { style: { width: '100%', height: '100%', - node: { + node: ({ colors: { default: theme.base0B, collapsed: theme.base0B, parent: theme.base0E, }, radius: 7, - }, - text: { + } as unknown) as string, + text: ({ colors: { default: theme.base0D, hover: theme.base06, }, - }, + } as unknown) as string, }, onClickText: this.onClickText, }; diff --git a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx index 00d97ffa..a70b2eae 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx +++ b/packages/redux-devtools-core/src/app/containers/monitors/InspectorWrapper/SubTabs.tsx @@ -11,6 +11,7 @@ import RawTab from './RawTab'; import ChartTab from './ChartTab'; import VisualDiffTab from './VisualDiffTab'; import { StoreState } from '../../../reducers'; +import { Delta } from 'jsondiffpatch'; type StateProps = ReturnType; type DispatchProps = ResolveThunks; @@ -19,7 +20,7 @@ type Props = StateProps & TabComponentProps>; class SubTabs extends Component { - tabs?: Tab[]; + tabs?: (Tab | Tab<{ data: unknown }> | Tab<{ data?: Delta }>)[]; constructor(props: Props) { super(props); @@ -56,7 +57,7 @@ class SubTabs extends Component { { name: 'Raw', component: VisualDiffTab, - selector: this.selector, + selector: this.selector as () => { data?: Delta }, }, ]; return; @@ -88,7 +89,7 @@ class SubTabs extends Component { return ( diff --git a/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx b/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx index 302ef95b..03a5fe4f 100644 --- a/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx +++ b/packages/redux-devtools-core/src/app/containers/monitors/Slider.tsx @@ -1,9 +1,10 @@ import React, { Component } from 'react'; import styled, { withTheme } from 'styled-components'; import SliderMonitor from 'redux-devtools-slider-monitor'; -import { LiftedAction, LiftedState } from 'redux-devtools-instrument'; -import { Action, Dispatch } from 'redux'; +import { LiftedAction } from 'redux-devtools-instrument'; +import { Action } from 'redux'; import { ThemeFromProvider } from 'devui'; +import { State } from '../../reducers/instances'; const SliderWrapper = styled.div` border-color: ${(props) => props.theme.base02}; @@ -12,8 +13,8 @@ const SliderWrapper = styled.div` `; interface Props { - liftedState: LiftedState, unknown>; - dispatch: Dispatch, unknown>>; + liftedState: State; + dispatch: (action: LiftedAction, unknown>) => void; theme: ThemeFromProvider; } @@ -29,6 +30,8 @@ class Slider extends Component { { this.store = store; store.dispatch({ type: CONNECT_REQUEST, - options: preloadedState!.connection || this.props.socketOptions, + options: (preloadedState!.connection || + this.props.socketOptions) as ConnectionOptions, }); this.forceUpdate(); }); @@ -29,21 +29,13 @@ class Root extends Component { render() { if (!this.store) return null; + const AppAsAny = App as any; return ( - + ); } } -Root.propTypes = { - socketOptions: PropTypes.shape({ - hostname: PropTypes.string, - port: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - autoReconnect: PropTypes.bool, - secure: PropTypes.bool, - }), -}; - export default Root; diff --git a/packages/redux-devtools-core/src/app/middlewares/api.ts b/packages/redux-devtools-core/src/app/middlewares/api.ts index 204cd41a..08f91ef3 100644 --- a/packages/redux-devtools-core/src/app/middlewares/api.ts +++ b/packages/redux-devtools-core/src/app/middlewares/api.ts @@ -13,23 +13,36 @@ import { GET_REPORT_ERROR, GET_REPORT_SUCCESS, } from '../constants/actionTypes'; -import { showNotification, importState, StoreAction } from '../actions'; +import { + showNotification, + importState, + StoreAction, + EmitAction, + LiftedActionAction, + Request, + DispatchAction, +} from '../actions'; import { nonReduxDispatch } from '../utils/monitorActions'; import { StoreState } from '../reducers'; let socket: SCClientSocket; let store: MiddlewareAPI, StoreState>; -function emit({ message: type, id, instanceId, action, state }) { +function emit({ message: type, id, instanceId, action, state }: EmitAction) { socket.emit(id ? 'sc-' + id : 'respond', { type, action, state, instanceId }); } -function startMonitoring(channel) { +function startMonitoring(channel: string) { if (channel !== store.getState().socket.baseChannel) return; store.dispatch({ type: actions.EMIT, message: 'START' }); } -function dispatchRemoteAction({ message, action, state, toAll }) { +function dispatchRemoteAction({ + message, + action, + state, + toAll, +}: LiftedActionAction) { const instances = store.getState().instances; const instanceId = getActiveInstance(instances); const id = !toAll && instances.options[instanceId].connectionId; @@ -41,7 +54,7 @@ function dispatchRemoteAction({ message, action, state, toAll }) { store, message, instanceId, - action, + action as DispatchAction, state, instances ), @@ -50,21 +63,32 @@ function dispatchRemoteAction({ message, action, state, toAll }) { }); } -interface DisconnectedAction { +interface RequestBase { + id?: string; + instanceId?: string; +} +interface DisconnectedAction extends RequestBase { type: 'DISCONNECTED'; id: string; } -interface StartAction { +interface StartAction extends RequestBase { type: 'START'; id: string; } -interface ErrorAction { +interface ErrorAction extends RequestBase { type: 'ERROR'; payload: string; } -type Request = DisconnectedAction | StartAction | ErrorAction; +interface RequestWithData extends RequestBase { + data: Request; +} +type MonitoringRequest = + | DisconnectedAction + | StartAction + | ErrorAction + | Request; -function monitoring(request: Request) { +function monitoring(request: MonitoringRequest) { if (request.type === 'DISCONNECTED') { store.dispatch({ type: REMOVE_INSTANCE, @@ -84,7 +108,9 @@ function monitoring(request: Request) { store.dispatch({ type: UPDATE_STATE, - request: request.data ? { ...request.data, id: request.id } : request, + request: ((request as unknown) as RequestWithData).data + ? { ...((request as unknown) as RequestWithData).data, id: request.id } + : request, }); const instances = store.getState().instances; @@ -110,7 +136,7 @@ function subscribe( const channel = socket.subscribe(channelName); if (subscription === UPDATE_STATE) channel.watch(monitoring); else { - const watcher = (request) => { + const watcher = (request: Request) => { store.dispatch({ type: subscription, request }); }; channel.watch(watcher); @@ -201,15 +227,19 @@ function login() { }); } -function getReport(reportId) { - socket.emit('getReport', reportId, (error, data) => { - if (error) { - store.dispatch({ type: GET_REPORT_ERROR, error }); - return; +function getReport(reportId: unknown) { + socket.emit( + 'getReport', + reportId, + (error: Error, data: { payload: string }) => { + if (error) { + store.dispatch({ type: GET_REPORT_ERROR, error }); + return; + } + store.dispatch({ type: GET_REPORT_SUCCESS, data }); + store.dispatch(importState(data.payload)); } - store.dispatch({ type: GET_REPORT_SUCCESS, data }); - store.dispatch(importState(data.payload)); - }); + ); } export default function api( diff --git a/packages/redux-devtools-core/src/app/middlewares/exportState.ts b/packages/redux-devtools-core/src/app/middlewares/exportState.ts index 9d0eab21..58cb9315 100644 --- a/packages/redux-devtools-core/src/app/middlewares/exportState.ts +++ b/packages/redux-devtools-core/src/app/middlewares/exportState.ts @@ -1,10 +1,13 @@ import stringifyJSON from '../utils/stringifyJSON'; import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes'; import { getActiveInstance } from '../reducers/instances'; +import { Dispatch, MiddlewareAPI } from 'redux'; +import { ExportRequest, StoreAction } from '../actions'; +import { StoreState } from '../reducers'; -let toExport; +let toExport: string | undefined; -function download(state) { +function download(state: string) { const blob = new Blob([state], { type: 'octet/stream' }); const href = window.URL.createObjectURL(blob); const a = document.createElement('a'); @@ -19,15 +22,17 @@ function download(state) { }, 0); } -const exportState = (store) => (next) => (action) => { +const exportState = ( + store: MiddlewareAPI, StoreState> +) => (next: Dispatch) => (action: StoreAction) => { const result = next(action); if ( toExport && action.type === UPDATE_STATE && - action.request.type === 'EXPORT' + action.request!.type === 'EXPORT' ) { - const request = action.request; + const request = action.request!; const id = request.instanceId || request.id; if (id === toExport) { toExport = undefined; @@ -35,7 +40,7 @@ const exportState = (store) => (next) => (action) => { JSON.stringify( { payload: request.payload, - preloadedState: request.committedState, + preloadedState: (request as ExportRequest).committedState, }, null, '\t' diff --git a/packages/redux-devtools-core/src/app/reducers/instances.ts b/packages/redux-devtools-core/src/app/reducers/instances.ts index ba95f485..0e17daea 100644 --- a/packages/redux-devtools-core/src/app/reducers/instances.ts +++ b/packages/redux-devtools-core/src/app/reducers/instances.ts @@ -89,19 +89,20 @@ function updateState( id: string, serialize: boolean | undefined ) { - let payload = request.payload; + let payload: State = request.payload as State; const actionsById = request.actionsById; if (actionsById) { payload = { + // eslint-disable-next-line @typescript-eslint/ban-types ...payload, actionsById: parseJSON(actionsById, serialize), computedStates: parseJSON(request.computedStates, serialize), - }; + } as State; if (request.type === 'STATE' && request.committedState) { payload.committedState = payload.computedStates[0].state; } } else { - payload = parseJSON(payload, serialize); + payload = parseJSON((payload as unknown) as string, serialize) as State; } let newState; @@ -112,11 +113,11 @@ function updateState( case 'INIT': newState = recompute(state.default, payload, { action: { type: '@@INIT' }, - timestamp: action.timestamp || Date.now(), + timestamp: (action as { timestamp?: unknown }).timestamp || Date.now(), }); break; case 'ACTION': { - let isExcess = request.isExcess; + const isExcess = request.isExcess; const nextActionId = request.nextActionId || liftedState.nextActionId + 1; const maxAge = request.maxAge; if (Array.isArray(action)) { @@ -125,7 +126,7 @@ function updateState( for (let i = 0; i < action.length; i++) { newState = recompute( newState, - request.batched ? payload : payload[i], + request.batched ? payload : ((payload as unknown) as State[])[i], action[i], newState.nextActionId + 1, maxAge, diff --git a/packages/redux-devtools-core/src/app/reducers/monitor.ts b/packages/redux-devtools-core/src/app/reducers/monitor.ts index ff9c68cf..8293d847 100644 --- a/packages/redux-devtools-core/src/app/reducers/monitor.ts +++ b/packages/redux-devtools-core/src/app/reducers/monitor.ts @@ -36,13 +36,12 @@ export function dispatchMonitorAction( ): MonitorState { return { ...state, - monitorState: - action.action.newMonitorState || + monitorState: (action.action.newMonitorState || action.monitorReducer( action.monitorProps, state.monitorState, action.action - ), + )) as MonitorStateMonitorState, }; } diff --git a/packages/redux-devtools-core/src/app/reducers/reports.ts b/packages/redux-devtools-core/src/app/reducers/reports.ts index 37376bed..66d9f6f1 100644 --- a/packages/redux-devtools-core/src/app/reducers/reports.ts +++ b/packages/redux-devtools-core/src/app/reducers/reports.ts @@ -3,8 +3,12 @@ import { } from '../constants/actionTypes'; import { StoreAction } from '../actions'; +export interface Data { + id: unknown; +} + export interface ReportsState { - data: unknown[]; + data: Data[]; } const initialState: ReportsState = { diff --git a/packages/redux-devtools-core/src/app/reducers/socket.ts b/packages/redux-devtools-core/src/app/reducers/socket.ts index b8cae6bf..ae8fc1b3 100644 --- a/packages/redux-devtools-core/src/app/reducers/socket.ts +++ b/packages/redux-devtools-core/src/app/reducers/socket.ts @@ -6,8 +6,10 @@ export interface SocketState { id: string | null; channels: string[]; socketState: States; - authState: AuthStates; + authState: AuthStates | 'pending'; error: Error | undefined; + baseChannel?: string; + authToken?: null; } const initialState: SocketState = { @@ -18,7 +20,10 @@ const initialState: SocketState = { error: undefined, }; -export default function socket(state = initialState, action: StoreAction) { +export default function socket( + state = initialState, + action: StoreAction +): SocketState { switch (action.type) { case actions.CONNECT_REQUEST: { return { diff --git a/packages/redux-devtools-core/src/app/store/configureStore.ts b/packages/redux-devtools-core/src/app/store/configureStore.ts index c7ff4ad9..fc8be313 100644 --- a/packages/redux-devtools-core/src/app/store/configureStore.ts +++ b/packages/redux-devtools-core/src/app/store/configureStore.ts @@ -25,15 +25,23 @@ export default function configureStore( deserialize: (data: unknown) => data, } as unknown) as PersistorConfig; + // eslint-disable-next-line @typescript-eslint/no-floating-promises getStoredState(persistConfig, (err, restoredState) => { let composeEnhancers = compose; if (process.env.NODE_ENV !== 'production') { - if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { - composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; + if ( + ((window as unknown) as { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose; + }).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ) { + composeEnhancers = ((window as unknown) as { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: typeof compose; + }).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; } if (module.hot) { // Enable Webpack hot module replacement for reducers module.hot.accept('../reducers', () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires const nextReducer = require('../reducers'); // eslint-disable-line global-require store.replaceReducer(nextReducer); }); diff --git a/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts b/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts index 76b5c15f..ff7f8fdb 100644 --- a/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts +++ b/packages/redux-devtools-core/src/app/utils/commitExcessActions.ts @@ -1,7 +1,9 @@ // Based on https://github.com/gaearon/redux-devtools/pull/241 /* eslint-disable no-param-reassign */ -export default function commitExcessActions(liftedState, n = 1) { +import { State } from '../reducers/instances'; + +export default function commitExcessActions(liftedState: State, n = 1) { // Auto-commits n-number of excess actions. let excess = n; let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1); diff --git a/packages/redux-devtools-core/src/app/utils/monitorActions.ts b/packages/redux-devtools-core/src/app/utils/monitorActions.ts index 3ed3cc80..1e5fc604 100644 --- a/packages/redux-devtools-core/src/app/utils/monitorActions.ts +++ b/packages/redux-devtools-core/src/app/utils/monitorActions.ts @@ -2,7 +2,10 @@ import difference from 'lodash/difference'; import omit from 'lodash/omit'; import stringifyJSON from './stringifyJSON'; import { SET_STATE } from '../constants/actionTypes'; -import { State } from '../reducers/instances'; +import { InstancesState, State } from '../reducers/instances'; +import { Dispatch, MiddlewareAPI } from 'redux'; +import { DispatchAction, StoreAction } from '../actions'; +import { StoreState } from '../reducers'; export function sweep(state: State): State { return { @@ -18,12 +21,12 @@ export function sweep(state: State): State { } export function nonReduxDispatch( - store, - message, - instanceId, - action, - initialState, - preInstances + store: MiddlewareAPI, StoreState>, + message: string, + instanceId: string, + action: DispatchAction, + initialState: string | undefined, + preInstances: InstancesState ) { const instances = preInstances || store.getState().instances; const state = instances.states[instanceId]; diff --git a/packages/redux-devtools-core/src/app/utils/parseJSON.ts b/packages/redux-devtools-core/src/app/utils/parseJSON.ts index c528eb60..3288fc20 100644 --- a/packages/redux-devtools-core/src/app/utils/parseJSON.ts +++ b/packages/redux-devtools-core/src/app/utils/parseJSON.ts @@ -1,17 +1,17 @@ import jsan from 'jsan'; import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes'; -export function reviver(key, value) { +export function reviver(key: string, value: unknown) { if ( typeof value === 'object' && value !== null && '__serializedType__' in value && - typeof value.data === 'object' + typeof (value as any).data === 'object' ) { - const data = value.data; - data[DATA_TYPE_KEY] = value.__serializedType__; + const data = (value as any).data; + data[DATA_TYPE_KEY] = (value as any).__serializedType__; if ('__serializedRef__' in value) - data[DATA_REF_KEY] = value.__serializedRef__; + data[DATA_REF_KEY] = (value as any).__serializedRef__; /* if (Array.isArray(data)) { data.__serializedType__ = value.__serializedType__; diff --git a/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts b/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts index d3191612..3765284c 100644 --- a/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts +++ b/packages/redux-devtools-core/src/app/utils/stringifyJSON.ts @@ -1,20 +1,21 @@ import jsan from 'jsan'; import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes'; -function replacer(key, value) { +function replacer(key: string, value: unknown) { if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) { - const __serializedType__ = value[DATA_TYPE_KEY]; + const __serializedType__ = (value as any)[DATA_TYPE_KEY]; const clone = { ...value }; - delete clone[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign + delete (clone as any)[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign const r = { data: clone, __serializedType__ }; - if (DATA_REF_KEY in value) r.__serializedRef__ = clone[DATA_REF_KEY]; + if (DATA_REF_KEY in value) + (r as any).__serializedRef__ = (clone as any)[DATA_REF_KEY]; return r; } return value; } -export default function stringifyJSON(data, serialize) { +export default function stringifyJSON(data: unknown, serialize: boolean) { return serialize - ? jsan.stringify(data, replacer, null, true) + ? jsan.stringify(data, replacer, (null as unknown) as undefined, true) : jsan.stringify(data); } diff --git a/packages/redux-devtools-core/src/app/utils/updateState.ts b/packages/redux-devtools-core/src/app/utils/updateState.ts index f802e272..c2b35bcf 100644 --- a/packages/redux-devtools-core/src/app/utils/updateState.ts +++ b/packages/redux-devtools-core/src/app/utils/updateState.ts @@ -1,10 +1,12 @@ import commitExcessActions from './commitExcessActions'; import { State } from '../reducers/instances'; +import { Action } from 'redux'; +import { PerformAction } from 'redux-devtools-instrument'; export function recompute( previousLiftedState: State, - storeState, - action, + storeState: State, + action: Action, nextActionId = 1, maxAge?: number, isExcess?: boolean @@ -21,12 +23,14 @@ export function recompute( liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId]; liftedState.actionsById = { ...liftedState.actionsById }; if (action.type === 'PERFORM_ACTION') { - liftedState.actionsById[actionId] = action; + liftedState.actionsById[actionId] = action as PerformAction< + Action + >; } else { liftedState.actionsById[actionId] = { - action: action.action || action, - timestamp: action.timestamp || Date.now(), - stack: action.stack, + action: (action as any).action || action, + timestamp: (action as any).timestamp || Date.now(), + stack: (action as any).stack, type: 'PERFORM_ACTION', }; } diff --git a/packages/redux-devtools-core/src/utils/catchErrors.ts b/packages/redux-devtools-core/src/utils/catchErrors.ts index b6d42219..a04d2148 100644 --- a/packages/redux-devtools-core/src/utils/catchErrors.ts +++ b/packages/redux-devtools-core/src/utils/catchErrors.ts @@ -1,28 +1,53 @@ const ERROR = '@@redux-devtools/ERROR'; -export default function catchErrors(sendError) { +interface ErrorAction { + type: typeof ERROR; + message?: Event | string; + url?: string | undefined; + lineNo?: number | undefined; + columnNo?: number | undefined; + stack?: string; + error?: Error; + isFatal?: boolean; + sourceURL?: string; + line?: number; + column?: number; +} + +export default function catchErrors( + sendError: (errorAction: ErrorAction) => void +) { if (typeof window === 'object' && typeof window.onerror === 'object') { window.onerror = function (message, url, lineNo, columnNo, error) { - const errorAction = { type: ERROR, message, url, lineNo, columnNo }; + const errorAction: ErrorAction = { + type: ERROR, + message, + url, + lineNo, + columnNo, + }; if (error && error.stack) errorAction.stack = error.stack; sendError(errorAction); return false; }; - } else if (typeof global !== 'undefined' && global.ErrorUtils) { - global.ErrorUtils.setGlobalHandler((error, isFatal) => { - sendError({ type: ERROR, error, isFatal }); - }); + } else if (typeof global !== 'undefined' && (global as any).ErrorUtils) { + (global as any).ErrorUtils.setGlobalHandler( + (error: Error, isFatal: boolean) => { + sendError({ type: ERROR, error, isFatal }); + } + ); } /* eslint-disable no-console */ if ( typeof console === 'object' && typeof console.error === 'function' && - !console.beforeRemotedev + !(console as any).beforeRemotedev ) { - console.beforeRemotedev = console.error.bind(console); + (console as any).beforeRemotedev = console.error.bind(console); console.error = function () { - let errorAction = { type: ERROR }; + let errorAction: ErrorAction = { type: ERROR }; + // eslint-disable-next-line prefer-rest-params const error = arguments[0]; errorAction.message = error.message ? error.message : error; if (error.sourceURL) { @@ -35,7 +60,8 @@ export default function catchErrors(sendError) { } if (error.stack) errorAction.stack = error.stack; sendError(errorAction); - console.beforeRemotedev.apply(null, arguments); + // eslint-disable-next-line prefer-rest-params + (console as any).beforeRemotedev.apply(null, arguments); }; } /* eslint-enable no-console */