Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web3.js extending the window interface type definitions

Web3.js web3 into the window object.

Browser Wallets like MetaMask inject ethereum into the window object.

In typescript right now to mitigate compile errors I'm casting as follows (window as any).ethereum

After looking in the Web3 repository and Wallet repos (such as MetaMask) there are no importable / copyable typescript definitions / interfaces for the Window object.

A possible solution is to write my own interface and extend the Window, look at the Window object and try to infer the types - not ideal

Other developers that have used web3.js and typescript, how did you get past the Window type interface issues and intellisense suggestions in VS Code?

like image 949
Xavier Avatar asked Dec 10 '22 23:12

Xavier


2 Answers

The official Metamask Provider repo now exports types you could/should use for extending the Window interface.

Same as in @Felipe's answer with MetamaskInpageProvider instead of Ethereumish,

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

declare global {
  interface Window {
    ethereum: MetaMaskInpageProvider;
  }
}

like image 156
Andrew Glago Avatar answered Dec 27 '22 05:12

Andrew Glago


I came across this just recently as well. I could not find an appropriate typings package from DefinitelyTyped so I started extrapolating from my own usage and the Metamask Documentation and created something that works so far.

Perhaps the community could edit this answer with their own contributions.

In order to use the ethereum object without TS complaints, I declare it in the window object:

declare global {
    interface Window {
        ethereum: Ethereumish;
    }
}

The makeshift Ethereum Provider types, Ethereumish looks like this:

import { ProviderMessage, ProviderRpcError, ProviderConnectInfo, RequestArguments } from 'hardhat/types';

export interface EthereumEvent {
    connect: ProviderConnectInfo;
    disconnect: ProviderRpcError;
    accountsChanged: Array<string>;
    chainChanged: string;
    message: ProviderMessage
}

type EventKeys = keyof EthereumEvent;
type EventHandler<K extends EventKeys> = (event: EthereumEvent[K]) => void;

export interface Ethereumish {
    autoRefreshOnNetworkChange: boolean;
    chainId: string;
    isMetaMask?: boolean;
    isStatus?: boolean;
    networkVersion: string;
    selectedAddress: any;

    on<K extends EventKeys>(event: K, eventHandler: EventHandler<K>): void;
    enable(): Promise<any>;
    request?: (request: { method: string, params?: Array<any> }) => Promise<any>
    /**
     * @deprecated
     */
    send?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
    sendAsync: (request: RequestArguments) => Promise<unknown>
}

As you can see, I have not been able to figure out the exact types of many things so far, but the important methods, send and sendAsync are accurate in my experience.

Another useful template is something I found inside @ethersproject/providers/src.ts/web3-provider.ts

export type ExternalProvider = {
    isMetaMask?: boolean;
    isStatus?: boolean;
    host?: string;
    path?: string;
    sendAsync?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
    send?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
    request?: (request: { method: string, params?: Array<any> }) => Promise<any>
}

this can be used when loading a new provider

new ethers.providers.Web3Provider(myProvider: ExternalProvider)
like image 20
Felipe Avatar answered Dec 27 '22 05:12

Felipe