如何在多文件中合并Function与Namespaces?
让TypeScript模块兼具函数调用与子方法访问能力
现有代码结构
我们的TypeScript代码按如下结构组织:
module/ ├── module.a.ts ├── module.b.ts ├── module.c.ts ├── module.barrel.ts └── index.ts
子模块示例(以module.a.ts为例)
每个子模块导出一个功能函数:
// module.a.ts export function a() { console.log('from A'); }
module.b.ts和module.c.ts结构类似,分别导出b()和c()函数,输出对应内容。
barrel文件(module.barrel.ts)
通过barrel文件统一导出所有子模块:
export * from './module.a.ts'; export * from './module.b.ts'; export * from './module.c.ts';
入口文件(原index.ts)
将barrel的导出内容作为命名空间导出:
export * as MyModule from './module.barrel';
当前用法
现在可以导入命名空间并调用子方法:
import { MyModule } from './module'; MyModule.a(); MyModule.b(); MyModule.c();
需求实现
我们需要修改index.ts,让MyModule既能作为函数直接调用(输出from ROOT MODULE),又能保留原有子方法的访问能力,支持如下用法:
import { MyModule } from './module'; MyModule(); // 输出 'from ROOT MODULE' MyModule.a(); // 输出 'from A' MyModule.b(); // 输出 'from B' MyModule.c(); // 输出 'from C'
修改后的index.ts代码
// 导入所有子模块的导出内容 import * as ModuleExports from './module.barrel'; // 定义根模块的函数逻辑,并合并类型 const MyModule = (() => { console.log('from ROOT MODULE'); }) as typeof ModuleExports & (() => void); // 将子模块的方法挂载到函数对象上 Object.assign(MyModule, ModuleExports); // 导出最终的模块 export { MyModule };
原理说明
- 函数对象挂载属性:JavaScript中函数本质是对象,因此可以通过
Object.assign将子模块的方法挂载到MyModule函数上。 - 类型合并:通过交叉类型
typeof ModuleExports & (() => void),让TypeScript识别MyModule既是一个可调用的函数,又拥有子模块的所有方法类型,避免类型报错。
内容的提问来源于stack exchange,提问作者mikoloism
相关产品推荐
相关产品推荐

