在 .d.ts 类型声明文件中引入其他类型?

我有一个 electron 项目,它有如下的目录结构:

src
 - main // 主进程
 - preload // preload
   - preload.ts
   - preload.d.ts
 - render // 渲染进程
 - shared // 共用

我想向渲染进程注入一些底层代码,于是我用了 preload:

// preload.ts
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'
import { IpcChannels } from '@shared/channelNames'

contextBridge.exposeInMainWorld('api', {
  ipcSend(channel: IpcChannels, ...data: any[]) {
    ipcRenderer.send(channel, ...data)
  },
  ipcSendSync(channel: IpcChannels, ...data: any[]) {
    return ipcRenderer.sendSync(channel, ...data)
  },
  ipcOn(channel: IpcChannels, listener: (event: IpcRendererEvent, ...args: any[]) => void) {
    ipcRenderer.on(channel, listener)
  },
  ipcOnce(channel: IpcChannels, listener: (event: IpcRendererEvent, ...args: any[]) => void) {
    ipcRenderer.once(channel, listener)
  },
  ipcOff(channel: IpcChannels) {
    ipcRenderer.removeAllListeners(channel)
  }
})
// channelNames.ts
export const WINDOW_MINIMIZE = 'WINDOW_MINIMIZE'
export const WINDOW_MAXIMIZE = 'WINDOW_MAXIMIZE'
export const WINDOW_UNMAXIMIZE = 'WINDOW_UNMAXIMIZE'
export const WINDOW_CLOSE = 'WINDOW_CLOSE'
export const IS_WINDOW_MAXIMIZE = 'IS_WINDOW_MAXIMIZE'

export type IpcChannels =
  | 'WINDOW_MINIMIZE'
  | 'WINDOW_MAXIMIZE'
  | 'WINDOW_UNMAXIMIZE'
  | 'WINDOW_CLOSE'
  | 'IS_WINDOW_MAXIMIZE'

我把 preload.d.ts 加到了渲染进程的 tsconfig.json 中的 include 数组里:

{
  "compilerOptions": {
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "baseUrl": ".",
    "paths": {
      "@@/*": ["../../*"],
      "@/*": ["*"],
      "@shared/*": ["../shared/*"]
    }
  },
  "include": [
    "./**/*.ts",
    "./**/*.tsx",
    "./**/*.less",
    "../shared/**/*.ts",
    "../../types/**/*.d.ts",
    "../preload/preload.d.ts"
  ]
}

然后我是这样写 preload.d.ts 的:

import { IpcChannels } from '@shared/channelNames'

type IpcListener = (event: Electron.IpcRendererEvent, ...args: any[]) => void

interface Api {
  readonly version: string
  readonly ipcSend(channel: IpcChannels, ...data: any[]): void
  readonly ipcSendSync(channel: IpcChannels, ...data: any[]): any
  readonly ipcOn(channel: IpcChannels, listener: IpcListener): void
  readonly ipcOnce(channel: IpcChannels, listener: IpcListener): void
  readonly ipcOff(channel: IpcChannels): void
}

interface Window {
  readonly api: Api
}

不过这样行不通,我键入 window.api 的时候没有获得任何提示,鼠标放到 api 上是显示的类型是 any

但如果我不使用 import 语句,而是把 IpcChannels 复制过来:

type IpcChannels =
  | 'WINDOW_MINIMIZE'
  | 'WINDOW_MAXIMIZE'
  | 'WINDOW_UNMAXIMIZE'
  | 'WINDOW_CLOSE'
  | 'IS_WINDOW_MAXIMIZE'

type IpcListener = (event: Electron.IpcRendererEvent, ...args: any[]) => void

interface Api {
  readonly version: string
  readonly ipcSend(channel: IpcChannels, ...data: any[]): void
  readonly ipcSendSync(channel: IpcChannels, ...data: any[]): any
  readonly ipcOn(channel: IpcChannels, listener: IpcListener): void
  readonly ipcOnce(channel: IpcChannels, listener: IpcListener): void
  readonly ipcOff(channel: IpcChannels): void
}

这样是可以的,window.api 的类型显示为 Api。但这样写我每次新加一个频道名就要改两个地方,有可能会忘。所有有什么好办法可以在 .d.ts 声明文件中引入其他 .ts 类型文件定义的类型吗?

阅读 5k
1 个回答

stackoverFlow上找到了同样的问题,答案在这里:
如何在.d.ts中引入类型

省流:
错误原因:

d.ts 文件仅在没有任何导入时才被视为环境模块声明.如果您提供了一个导入行,它现在被视为一个普通的模块文件,而不是全局文件,因此增加模块定义不起作用.

解决方案:TS2.9开始支持使用import()语法引入类型。

declare namespace Express {
  interface Request {
    user: import("./user").User;
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题