You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为CommonJS JS模块添加TS接口,实现类与接口同时导入

问题:为CommonJS规范的JS文件扩展TS接口声明的实现问题

我有一个开启了allowJS配置的TypeScript NodeJS项目,其中一个CommonJS规范的JavaScript文件包含Logger类。我希望为这个JS文件扩展ILogger接口声明,这样就能在TypeScript文件中使用import {Logger, ILogger} from './logger';的方式导入。
根据相关技术文档的说明,TypeScript不支持JSDoc的@interface注解,因此需要使用.d.ts声明文件实现。但我未找到将包含类的JS文件和包含接口的声明文件结合、让二者都能从TS文件导入的方法,以下是我的三次尝试及对应问题:

尝试1:同命名logger.js + logger.d.ts,TypeScript仅读取d.ts类型

将类放在js文件,接口放在同名d.ts文件的方案不生效,TypeScript只会从d.ts文件读取类型,忽略JS文件中的类:
报错信息:app.ts:1:18 - error TS2724: '"./logger"' has no exported member named 'Logger'. Did you mean 'ILogger'?
相关代码:

// logger.js
//@ts-check
exports.Logger = class Logger {
  /**
   * @param {string} msg 
   * @returns {void}
   */
  info(msg) {
    console.log(msg);
  }
}
// logger.d.ts
export interface ILogger {
  info(msg: string): void
}
// app.ts
import {ILogger, Logger} from './logger';

export function f(logger: ILogger) {
  logger.info('f');
}

export function main() {
  const logger = new Logger();
  f(logger);
}
// tsconfig.json
{
  "extends": "@tsconfig/recommended/tsconfig.json",
  "compilerOptions": {
    "allowJs": true
  }
}
// package.json
{
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.1",
    "typescript": "^4.4.3"
  }
}

尝试2:通过三斜杠指令引用.d.ts做模块扩展,TypeScript仅读取logger.js的类

我参考模块扩展(declare module '…')方案,用三斜杠指令(<reference path="…"/>)引用声明文件扩展./logger模块,但扩展不生效,TypeScript仅读取JS文件中的类,忽略declare module的声明:
报错信息:app.ts:2:9 - error TS2724: '"./logger"' has no exported member named 'ILogger'. Did you mean 'Logger'?
我添加的全局声明没有触发TypeScript报错,说明types.d.ts文件被正常读取了。
相关代码:

// types.d.ts:
declare module './logger' {
  export interface ILogger {
    info(msg: string): void
  }
}
declare function myGlobalFunc(): void
// app.ts:
/// <reference path="./types.d.ts"/>
import {ILogger, Logger} from './logger';

export function f(logger: ILogger) {
  logger.info('f');
}

export function main() {
  const logger = new Logger();
  myGlobalFunc();
  f(logger);
}

其余logger.js、tsconfig.json、package.json代码同尝试1。

尝试3:在app.ts内直接扩展logger.js模块可生效,但复用性差

我在TypeScript模块内直接对./logger做模块扩展,没有触发TypeScript报错,可以正常运行。但该方案的问题是每次使用时都需要重复写模块扩展代码,或者额外导入做了扩展的TS模块,复用性差。
相关代码:

// app.ts
import {ILogger, Logger} from './logger';

declare module './logger' {
  export interface ILogger {
    info(msg: string): void
  }
}

export function f(logger: ILogger) {
  logger.info('f');
}

export function main() {
  const logger = new Logger();
  f(logger);
}

其余logger.js、tsconfig.json、package.json代码同尝试1。
请问有没有更优的方案,可以为JavaScript CommonJS模块添加TypeScript接口声明?

解决方案

方案1:补全同名声明文件(推荐)

尝试1失效的核心原因是:当存在同名.d.ts文件时,TypeScript会优先读取声明文件的类型定义,不会再自动推导JS文件的导出内容,只需要在声明文件中补全JS文件已有导出的类型即可:
修改logger.d.ts内容如下:

// 声明JS文件中实际导出的Logger类的类型
export class Logger {
  info(msg: string): void
}
// 声明新增的ILogger接口
export interface ILogger {
  info(msg: string): void
}

不需要额外修改其他配置,即可直接在任意TS文件中通过import {Logger, ILogger} from './logger'正常导入,类型检查和JS运行逻辑都不会受影响,后续Logger类有方法更新时同步修改声明文件即可。

方案2:JSDoc定义接口(无需额外声明文件)

如果不想单独维护.d.ts文件,也可以直接在logger.js中通过JSDoc的@typedef定义接口,TypeScript可直接识别该类型:
修改logger.js内容如下:

// logger.js
//@ts-check
/**
 * @typedef {object} ILogger
 * @property {(msg: string) => void} info
 */
exports.Logger = class Logger {
  /**
   * @param {string} msg 
   * @returns {void}
   */
  info(msg) {
    console.log(msg);
  }
}

该方案不需要额外的声明文件,也可以正常导入ILogger和Logger使用。

内容的提问来源于stack exchange,提问作者yonran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 17:15:01