如何用TypeScript从指定目录动态加载类并生成可实例化的Map集合
实现方案
动态批量导入目录文件并生成类映射的实现逻辑和你的运行/构建环境强相关,以下是不同场景的可用方案:
前置约定
默认你Shapes目录下的每个文件导出规则统一:要么默认导出对应类,要么导出与文件名同名的命名类,示例:
// Shapes/Square.ts 示例 export default class Square { // 类业务逻辑 }
同时提前定义Shape基类类型约束:
interface Shape { // 所有形状类的公共属性/方法定义 }
1. Node.js 原生环境(TS编译后运行在Node服务端)
直接用Node内置的fs、path模块读取目录+动态require实现:
import * as fs from 'fs' import * as path from 'path' export class Application { static getShapes(): Map<string, new () => Shape> { const shapeMap = new Map<string, new () => Shape>() // 按你实际项目路径调整Shapes目录的绝对路径 const shapesDir = path.resolve(__dirname, './Shapes') // 读取目录下所有文件 const files = fs.readdirSync(shapesDir) for (const file of files) { // 过滤非代码文件 if (!file.endsWith('.ts') && !file.endsWith('.js')) continue // 提取不带后缀的文件名作为Map的key const fileName = path.basename(file, path.extname(file)) // 动态导入模块 const module = require(path.join(shapesDir, file)) // 取导出的类,默认导出取module.default,命名导出取module[fileName] const ShapeClass = module.default || module[fileName] // 校验是可构造的类再存入Map if (typeof ShapeClass === 'function' && ShapeClass.prototype.constructor) { shapeMap.set(fileName, ShapeClass) } } return shapeMap } }
使用方式和你的预期完全一致:
const instances = Application.getShapes() const square = new (instances.get("Square")!)()
2. Vite 前端环境
用Vite内置的import.meta.globAPI实现批量导入,不需要操作文件系统:
export class Application { static async getShapes(): Promise<Map<string, new () => Shape>> { const shapeMap = new Map<string, new () => Shape>() // 批量匹配Shapes目录下所有ts文件,eager设为true表示直接同步导入所有模块 const modules = import.meta.glob('./Shapes/*.ts', { eager: true }) for (const [filePath, module] of Object.entries(modules)) { const fileName = filePath.split('/').pop()?.replace(/\.(ts|js)$/, '') as string const ShapeClass = (module as any).default || (module as any)[fileName] if (typeof ShapeClass === 'function' && ShapeClass.prototype.constructor) { shapeMap.set(fileName, ShapeClass) } } return shapeMap } }
使用时因为是异步API,需要加await:
const instances = await Application.getShapes() const square = new (instances.get("Square")!)()
3. Webpack 前端环境
用Webpack内置的require.contextAPI实现批量导入:
export class Application { static getShapes(): Map<string, new () => Shape> { const shapeMap = new Map<string, new () => Shape>() // 三个参数分别是:目标目录、是否遍历子目录、匹配文件的正则 const context = require.context('./Shapes', false, /\.ts$/) context.keys().forEach((filePath: string) => { const fileName = filePath.replace(/^\.\/(.*)\.\w+$/, '$1') const module = context(filePath) const ShapeClass = module.default || module[fileName] if (typeof ShapeClass === 'function' && ShapeClass.prototype.constructor) { shapeMap.set(fileName, ShapeClass) } }) return shapeMap } }
注意事项
- 如果你的类构造函数需要传参,把Map的泛型改成
new (...args: any[]) => Shape即可 - 新增形状类只需要放在Shapes目录下,不需要手动修改导入逻辑,会自动被识别加入映射
- 生产构建时批量导入的文件默认会全部打包,不会被tree shaking误删,不需要额外配置
内容的提问来源于stack exchange,提问作者Ahmed Osama
相关产品推荐
相关产品推荐

