Error with Redux DevTools Extension using TS: "Property '__REDUX_DEVTOOLS_EXTENSION_COMPOSE__' does not exist on type 'Window'."?

41,279

Solution 1

This is how you can use redux-dev-tools in a typescript react application.

Create global Interface for the Window object:

declare global {
  interface Window {
    __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
  }
}

Then, create composeEnhancers as follows:

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

Then create a store.

const store = createStore(rootReducers, composeEnhancers());

rootReducers - in my case refers to combinedReducers created in a surparate file.

Now you can use Provider as usual in React.js as:

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

All the code in the index.tsx

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import rootReducers from "./reducers";

import { Provider } from "react-redux";
import { createStore, compose, applyMiddleware } from "redux";

declare global {
  interface Window {
    __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
  }
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducers, composeEnhancers());

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);
reportWebVitals();

Solution 2

This is a special case of this question. Redux doesn't provide types for __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ because this function is exposed by Redux DevTools, not Redux itself.

It's either:

const composeEnhancers = window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] as typeof compose || compose;

Or:

declare global {
    interface Window {
      __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
    }
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

This is already done by redux-devtools-extension package that contains TypeScript typings. If it's installed, its imports should be used instead of accessing __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ manually.

Solution 3

The most streamlined way to make this work with TypeScript is to use the redux-devtools-extension and install as a dev dependency as follows:

npm install --save-dev redux-devtools-extension

The next step for those new to redux and these developer tools was confusing and unclear. The docs all have code like the following:

const store = createStore(reducer, composeWithDevTools(
  applyMiddleware(...middleware),
  // other store enhancers if any
));

The problem is I don't have any middleware configured so this wasn't working. In it's most primitive usage, this is all you need:

import { composeWithDevTools } from 'redux-devtools-extension';

const store = createStore(myReducer, composeWithDevTools());

At this point if you click the extension in the browser and there is a valid redux store, you will be able to inspect the state.

This is an alternative approach to using (window as any) and also clears up just exaclty how to use the redux-devtools-extension in its minimal form.

Solution 4

My approach to the issue was the following:

export const composeEnhancers =
  (window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;

Solution 5

Working as a charm:

const store = createStore(
    rootReducer,
    initialState,
    compose(
        applyMiddleware(...middleware),
        (window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__()
    )       

);
Share:
41,279
justkeithcarr
Author by

justkeithcarr

Updated on August 29, 2021

Comments

  • justkeithcarr
    justkeithcarr almost 3 years

    I'm getting this error on my index.tsx.

    Property 'REDUX_DEVTOOLS_EXTENSION_COMPOSE' does not exist on type 'Window'.

    Here is my index.tsx code:

    import * as React from 'react';
    import * as ReactDOM from 'react-dom';
    import App from './App';
    import './index.css';
    import registerServiceWorker from './registerServiceWorker';
    
    import { Provider } from 'react-redux';
    
    import { createStore, compose, applyMiddleware } from 'redux';
    import rootReducer from './store/reducers';
    
    import thunk from 'redux-thunk';
    
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    
     const store = createStore(rootReducer, composeEnhancers(
         applyMiddleware(thunk)
     ));
    
    ReactDOM.render(  <Provider store={store}><App /></Provider>, document.getElementById('root'));
    
    registerServiceWorker();
    

    I've installed @types/npm install --save-dev redux-devtools-extension and I'm using create-react-app-typescript. Thanks alot for any tips for what's going on in advance.

  • justkeithcarr
    justkeithcarr over 5 years
    Thanks so much for this @etus, you're a life savor!!
  • Estus Flask
    Estus Flask over 5 years
    Glad it helped.
  • Peppe
    Peppe almost 5 years
    Using window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] I get an error saying that window uses numeric index while we set a string...
  • Estus Flask
    Estus Flask almost 5 years
    @Peppe The problem is likely specific to your setup, old TS version or messed up typings. You can try (window as any)['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] as a dirty fix. Any way, redux-devtools-extension is a good way to solve this.
  • Federico Viotti
    Federico Viotti over 3 years
    I think this solution using redux-devtools-extension from npm is the cleaner one. I used it and works great.
  • Baggio Wong
    Baggio Wong over 3 years
    Not to add noise, but this looks much more proper and should be accepted as the answer (especially since the OP didn't state they can't import composeWithDevTools for whatever reason). And we don't have to add more as any's!
  • pmiranda
    pmiranda over 3 years
    But what if you can't use any as a type?
  • Samson
    Samson about 2 years
    I am facing an issue saying unexpected token at declare global
  • Kristiyan Tsvetanov
    Kristiyan Tsvetanov almost 2 years
    Getting a suggestion: We recommend using the configureStore method of the @reduxjs/toolkit package, which replaces createStore. Redux Toolkit is our recommended approach for writing Redux logic today, including store setup, reducers, data fetching, and more. configureStore from Redux Toolkit is an improved version of createStore that simplifies setup and helps avoid common bugs.