Search code examples
reactjstypescriptethereumweb3js

How do I resolve "ethereum.request cannot find name 'ethereum'"


I'm using metamask/detect-provider to make a simple button that connects to the metamask extension following the metamask documentation. However, it returns

Typescript error Cannot find name 'ethereum'. TS3204 when I do npm start. Does anyone know the reason for this error?

import Web3 from 'web3';
import { Message, Button } from "semantic-ui-react";
import 'semantic-ui-css/semantic.min.css';
import detectEthereumProvider from '@metamask/detect-provider';
import './App.css';

function App() {
  const loadMetamask = () => {
    ethereum.request({ method: 'eth_requestAccounts' });
  }
  return (
    <div className="App">
      <div className="App-header">
        <h1>Testing</h1>

        <Message warning>Metamask is not connected</Message>
        <button color="green"
          onClick={() => loadMetamask()}
        >Connect to Metamask</button>
      </div>
    </div>
  );
}
export default App;

Solution

  • This is due to typescript compiler couldn't find the ethereum module as ethereum module is in global window.

    There are few ways to solve it.

    First way, create your own type definition for window.ethereum. You may refer to here Web3.js extending the window interface type definitions

    Second way, ask typescript compiler to ignore the error, which is not recommended as it beat the purpose of using typescript.

    //@ts-ignore
     ethereum.request({ method: 'eth_requestAccounts' });
    

    Last way, which is the laziest way. @metamask/provides did provide the type definition for window.ethereum. Therefore, we install it by running

    npm i @metamask/providers
    

    After that, import the class

    import { MetaMaskInpageProvider } from '@metamask/providers';
    

    Then, tell the typescript compiler to treat window.ethereum as MetaMaskInpageProvider

    const ethereum = window.ethereum as MetaMaskInpageProvider;
    

    Now, you should be able to

    ethereum.request<string[]>({ method: 'eth_requestAccounts' });
    

    Your code should looks similar to below

    import Web3 from 'web3';
    import { Message, Button } from "semantic-ui-react";
    import 'semantic-ui-css/semantic.min.css';
    import detectEthereumProvider from '@metamask/detect-provider';
    import { MetaMaskInpageProvider } from '@metamask/providers';
    import './App.css';
    
    function App() {
      const loadMetamask = async () => {
        // You need to await for user response on the metamask popup dialog
        const accounts = await ethereum.request<string[]>({ method: 'eth_requestAccounts' });
        if(accounts){
           console.log(accounts[0]);
        }
      }
      return (
        <div className="App">
          <div className="App-header">
            <h1>Testing</h1>
    
            <Message warning>Metamask is not connected</Message>
            <button color="green"
              onClick={() => loadMetamask()}
            >Connect to Metamask</button>
          </div>
        </div>
      );
    }
    export default App;
    

    Even though it works, but we installed unused @metamask/providers library.