TypeScript如何加载JS文件中的schema变量并合并多文件内容?
实现TypeScript中加载多个JS Schema文件并合并的方案
我来一步步拆解这个需求,给你具体的实现方案:
1. 先调整JS Schema文件的导出方式
你的原始JS文件只是直接定义了var schema,但Node.js里要安全加载这个变量,最规范的做法是让文件导出它。修改后的JS文件长这样:
// schema1.js module.exports = { "date": Date.now(), "someOtherField": 5 + 6, "aMoreComplexField": { "foo": "bar" } };
要是你实在没法修改原JS文件,后面我也会给你一个应急方案,但优先选上面这种导出方式,更安全也更易维护。
2. TypeScript中的核心实现
根据你的需求,我分两种合并场景给出代码:浅合并(适合无嵌套或允许嵌套字段被覆盖)和深合并(保留嵌套对象的属性)。
基础版:浅合并
浅合并用Object.assign即可,后续加载的文件会覆盖前面的同名字段。我们先给Schema定义类型,让TS提供类型提示和检查:
import * as path from 'path'; // 定义Schema的类型,按需扩展字段 type Schema = { date: number; someOtherField?: number; aMoreComplexField?: { foo?: string; }; // 允许其他任意字段 [key: string]: any; }; function loadSchema(...schemaFiles: string[]): Schema { let mergedSchema: Schema = {}; for (const file of schemaFiles) { // 转成绝对路径,避免相对路径的坑 const filePath = path.resolve(file); // 加载JS文件,用类型断言让TS识别结构 const fileSchema = require(filePath) as Schema; // 合并到结果对象 mergedSchema = Object.assign(mergedSchema, fileSchema); } // 这里添加你需要的额外操作,比如新增一个加载时间字段 mergedSchema.loadTime = Date.now(); return mergedSchema; } // 调用示例 const combinedSchema = loadSchema('./schema1.js', './schema2.js'); console.log(combinedSchema);
进阶版:深层合并
如果Schema包含嵌套对象,浅合并会直接覆盖整个嵌套对象,这时候需要用深合并。你可以自己实现一个简单的深合并函数,或者用lodash的merge(需先安装lodash包)。
先看自定义的深合并实现:
// 简单的深合并函数,支持对象嵌套,数组直接覆盖(可按需调整) function deepMerge(target: any, source: any): any { const merged = { ...target }; for (const key in source) { if (source.hasOwnProperty(key)) { // 如果是对象且不是数组,递归合并 if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) { merged[key] = deepMerge(target[key] || {}, source[key]); } else { // 基本类型和数组直接覆盖 merged[key] = source[key]; } } } return merged; } // 修改loadSchema里的合并逻辑 function loadSchema(...schemaFiles: string[]): Schema { let mergedSchema: Schema = {}; for (const file of schemaFiles) { const filePath = path.resolve(file); const fileSchema = require(filePath) as Schema; // 用深合并替代Object.assign mergedSchema = deepMerge(mergedSchema, fileSchema); } // 额外操作示例 mergedSchema.loadTime = Date.now(); return mergedSchema; }
3. 一些关键注意事项
- 类型安全:定义
Schema类型能帮你在开发时避免类型错误,TS会实时给出提示,大幅提升代码可靠性。 - 文件路径:务必用
path.resolve把相对路径转成绝对路径,不然在不同目录下运行代码可能出现文件找不到的问题。 - 应急方案(不推荐):如果完全无法修改原JS文件,只能加载未导出的
var schema,可以用fs读取文件内容再eval——但强烈不推荐,因为eval会执行任意代码,存在安全风险。示例代码:import * as fs from 'fs'; import * as path from 'path'; function loadUnmodifiedSchema(file: string): Schema { const filePath = path.resolve(file); const fileContent = fs.readFileSync(filePath, 'utf8'); const context = {}; // 执行文件代码,把schema变量存入context eval(`var schema; ${fileContent}; context.schema = schema;`); return context.schema as Schema; } - ES模块适配:如果你的TS项目用ES模块(tsconfig.json中
"module": "ESNext"),可以用动态导入import()加载文件,此时函数要改成异步:async function loadSchema(...schemaFiles: string[]): Promise<Schema> { let mergedSchema: Schema = {}; for (const file of schemaFiles) { const filePath = path.resolve(file); // 动态导入JS文件 const { default: fileSchema } = await import(filePath); mergedSchema = deepMerge(mergedSchema, fileSchema); } mergedSchema.loadTime = Date.now(); return mergedSchema; }
内容的提问来源于stack exchange,提问作者Eydamos
相关产品推荐
相关产品推荐

