Web3.js 扩展 window 接口类型定义

Web3.js extending the window interface type definitions

Web3.js web3 进入 window 对象。

MetaMask 这样的浏览器钱包将 ethereum 注入 window 对象。

现在在 typescript 中以减轻编译错误,我按如下方式进行转换 (window as any).ethereum

查看 Web3 存储库和钱包存储库(例如 MetaMask)后,Window 对象没有可导入/可复制的打字稿定义/接口。

一个可能的解决方案是编写我自己的接口并扩展 Window,查看 Window 对象并尝试推断类型 - 不理想

其他使用过 web3.js 和 typescript 的开发者,你们是如何解决 Window 类型接口问题和 VSCode 中的智能感知建议的?

我最近也遇到了这个问题。我找不到合适的 typings package from DefinitelyTyped so I started extrapolating from my own usage and the Metamask Documentation 并创建了一些到目前为止有效的东西。

也许社区可以用自己的贡献来编辑这个答案。

为了使用ethereum对象没有TS投诉,我在window对象中声明:

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

临时的以太坊供应商类型,Ethereumish 看起来像这样:

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>
}

如您所见,到目前为止我还不能弄清楚很多东西的确切类型,但重要的方法 sendsendAsync 根据我的经验是准确的。

另一个有用的模板是我在@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>
}

这可以在加载新的提供程序时使用

new ethers.providers.Web3Provider(myProvider: ExternalProvider)

官方 Metamask Provider 存储库现在导出您 could/should 用于扩展 Window 接口的类型。

与@Felipe 的回答相同,使用 MetamaskInpageProvider 而不是 Ethereumish

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

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

我会在这里转储我目前使用的东西。

src/{anything}.ts 例如src/interfaces.d.ts
interface Window {
  // pick one
  ethereum: EthereumProvider
  // ethereum: ExternalProvider
  // ethereum: AbstractProvider
}

// ExternalProvider seems to be the official ethersproject type for the window.ethereum object, however, `new Web3(ethereum)` does not like it so we must improvise.
declare type ExternalProvider = import('@ethersproject/providers').ExternalProvider
declare type AbstractProvider = import('web3/node_modules/web3-core/types').AbstractProvider
interface EthereumProvider extends ExternalProvider {
  _state: any
  sendAsync: AbstractProvider['sendAsync']
}

此文件是一个脚本,因为它不导入和导出任何内容(与模块不同),使其声明环境 - 全局可用。只需确保它包含在 include/blob 数组 "include": ["..."] 中的 tsconfig.json 文件中。

更多阅读:
https://github.com/MetaMask/providers
github.com~ethers.js @ ExternalProvider