Electron preload.ts 类型无法自动推导的解决方案

24 阅读1分钟

Electron preload.ts 类型无法自动推导的解决方案

在 Electron 中通过 contextBridge.exposeInMainWorld() 暴露 API:

// preload.ts
import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('electron', {
  puppeteer: () => ipcRenderer.invoke('puppeteer'),
  db: () => ipcRenderer.invoke('db'),
});

Renderer 中调用:

await window.electron.puppeteer();

TypeScript 会报错:

Property 'electron' does not exist on type 'Window & typeof globalThis'

原因是:

contextBridge.exposeInMainWorld() 只是在运行时向 window 注入对象,TypeScript 并不会根据 preload.ts 自动推导出:

window.electron

的类型。

因此需要手动定义类型声明,并让 preload.ts 和 Renderer 共用同一套类型。

1. 定义 Electron API 类型

创建:

src/types/electron.ts
export interface ElectronAPI {
  puppeteer(): Promise<void>;
  db(): Promise<unknown>;
}

以后所有暴露给 Renderer 的 Electron API,都统一维护在这里。

2. preload.ts 使用同一个类型

import { contextBridge, ipcRenderer } from 'electron';
import type { ElectronAPI } from './types/electron';

const electronAPI: ElectronAPI = {
  puppeteer: () => ipcRenderer.invoke('puppeteer'),
  db: () => ipcRenderer.invoke('db'),
};

contextBridge.exposeInMainWorld('electron', electronAPI);

这样 preload.ts 本身也会受到 TypeScript 类型检查。

例如 ElectronAPI 中声明了:

puppeteer(): Promise<void>;

但 electronAPI 中漏掉了这个方法,TypeScript 会直接提示错误。

这样可以避免接口类型和实际 preload 实现不一致。

3. 给 window.electron 增加全局类型

创建:

src/types/global.d.ts
import type { ElectronAPI } from './electron';

declare global {
  interface Window {
    electron: ElectronAPI;
  }
}

export {};

之后 Renderer 中就可以直接使用:

await window.electron.puppeteer();

const result = await window.electron.db();

同时也会有完整的 IDE 自动补全和 TypeScript 类型检查。