docs/guides/electron-api-best-practices.md
保持简单,直接调用,通过类型定义解决 IDE 警告
在 packages/ui/src/types/electron.d.ts 中定义完整的 API 类型:
declare global {
interface Window {
electronAPI: {
updater: {
checkAllVersions(): Promise<{
currentVersion: string
stable?: {
remoteVersion?: string
hasUpdate?: boolean
message?: string
releaseDate?: string
releaseNotes?: string
remoteReleaseUrl?: string
}
prerelease?: {
remoteVersion?: string
hasUpdate?: boolean
message?: string
releaseDate?: string
releaseNotes?: string
remoteReleaseUrl?: string
}
}>
installUpdate(): Promise<void>
ignoreVersion(version: string, versionType?: 'stable' | 'prerelease'): Promise<void>
downloadSpecificVersion(versionType: 'stable' | 'prerelease'): Promise<{
hasUpdate: boolean
message: string
version?: string
reason?: 'ignored' | 'latest' | 'error'
}>
}
shell: {
openExternal(url: string): Promise<void>
showItemInFolder(path: string): Promise<void>
}
on: (event: string, callback: Function) => void
off: (event: string, callback: Function) => void
}
}
}
在业务代码中直接调用,无需包装:
// ✅ 正确的使用方式
export function useUpdater() {
const checkBothVersions = async () => {
try {
// 直接调用,类型安全,无 IDE 警告
const results = await window.electronAPI!.updater.checkAllVersions()
// 直接使用返回的数据
console.log('Current version:', results.currentVersion)
if (results.stable?.hasUpdate) {
console.log('Stable update available:', results.stable.remoteVersion)
}
return results
} catch (error) {
console.error('Version check failed:', error)
throw error
}
}
const installUpdate = async () => {
try {
await window.electronAPI!.updater.installUpdate()
console.log('Update installation initiated')
} catch (error) {
console.error('Install failed:', error)
}
}
const openReleaseUrl = async (url: string) => {
try {
await window.electronAPI!.shell.openExternal(url)
} catch (error) {
console.error('Failed to open URL:', error)
}
}
return {
checkBothVersions,
installUpdate,
openReleaseUrl
}
}
// ✅ 正确的事件监听
const setupEventListeners = () => {
if (!window.electronAPI?.on) return
const updateAvailableListener = (info: any) => {
console.log('Update available:', info)
}
window.electronAPI.on('update-available-info', updateAvailableListener)
// 清理函数
return () => {
if (window.electronAPI?.off) {
window.electronAPI.off('update-available-info', updateAvailableListener)
}
}
}
// ❌ 错误:不必要的包装层
const useElectronAPI = () => {
const safeCall = async (apiCall) => {
try {
const data = await apiCall()
return { success: true, data }
} catch (error) {
return { success: false, error: error.message }
}
}
return {
updater: {
checkAllVersions: () => safeCall(() => window.electronAPI.updater.checkAllVersions())
}
}
}
// ❌ 错误:引入不必要的包装格式
const response = await electronAPI.updater.checkAllVersions()
if (!response.success) { // 增加了复杂性
throw new Error(response.error)
}
const data = response.data // 多余的解包
保持 preload.js 的简洁性:
// ✅ 正确:简单直接
const electronAPI = {
updater: {
checkAllVersions: async () => {
const result = await ipcRenderer.invoke('update-check-all-versions')
if (!result.success) {
throw new Error(result.error)
}
return result.data // 直接返回数据
},
installUpdate: async () => {
const result = await ipcRenderer.invoke('update-install')
if (!result.success) {
throw new Error(result.error)
}
// void 返回,无需返回数据
}
},
shell: {
openExternal: async (url) => {
const result = await ipcRenderer.invoke('shell-open-external', url)
if (!result.success) {
throw new Error(result.error)
}
// void 返回
}
},
on: (event, callback) => ipcRenderer.on(event, callback),
off: (event, callback) => ipcRenderer.off(event, callback)
}
contextBridge.exposeInMainWorld('electronAPI', electronAPI)
记住: 最好的抽象就是没有抽象。只在真正需要时才引入复杂性。