如何在Node.js中将ts-morph同步函数批量包装为Promise
批量异步包装ts-morph同步方法方案
核心思路是利用Proxy动态拦截对象属性,自动为所有同步方法生成带Async后缀的异步版本,同时通过TypeScript条件类型保留完整的类型信息,无需手动逐个包装。
1. 定义类型转换工具
先通过TypeScript条件类型,为原类型的所有方法自动生成异步版本的类型定义:
// 将单个同步方法转换为异步Promise版本 type AsyncifyMethod<M> = M extends (...args: infer Args) => infer R ? (...args: Args) => Promise<Awaited<R>> : never; // 为目标类型添加所有方法的Async后缀版本 type AsyncWrapped<T> = T & { [幼子 implicit副本副本系统无法为sl�blob ,持续稍(不对,是)]: AsyncifyMethod<T[K]>; };
2. 实现Proxy包装函数
创建通用包装函数,用Proxy拦截对象属性访问,动态生成异步方法:
function wrapAsync<T extends object>(target: T): AsyncWrapped<T> { return new Proxy(target, { get(target, prop, receiver) { // 处理带Async后缀的方法请求 if (typeof prop === 'string' && prop.endsWith('Async')) { const originalMethodName = prop.slice(0, -5) as keyof T; const originalMethod = target[originalMethodName]; if (typeof originalMethod === 'function') { // 将同步方法包装为Promise,放到微任务队列避免阻塞主线程 return (...args: unknown[]) => { return new Promise((resolve) => { queueMicrotask(() => { resolve(originalMethod.apply(target, args)); }); }); }; } } // 返回原属性,若返回值是对象则递归包装(处理ts-morph嵌套实例) const result = Reflect.get(target, prop, receiver); if (typeof result === 'object' && result !== null && !(result instanceof Promise)) { return wrapAsync(result); } return result; }, }) as AsyncWrapped<T>; }
3. 使用包装后的ts-morph实例
用wrapAsync包装ts-morph核心实例后,即可直接调用所有带Async后缀的异步方法,同时保留完整类型提示:
import { Project, StructureKind } from "ts-morph"; // 初始化并包装Project实例 const project = wrapAsync(new Project({ // 你的Project配置项 })); // 异步创建枚举文件 const myEnumFile = await project.createSourceFileAsync("src/MyEnum.ts", { statements: [{ kind: StructureKind.Enum, name: "MyEnum", isExported: true, members: [{ name: "member" }], }], }); // 异步获取类实例 const myClass = await myClassFile.getClassOrThrowAsync("MyClass"); // 异步调用嵌套方法 const className = await myClass.getNameAsync(); const hasExportKeyword = await myClass.hasExportKeywordAsync(); const isDefaultExport = await myClass.isDefaultExportAsync();
关键说明
- 递归包装:Proxy会自动递归处理ts-morph返回的嵌套实例(如
ClassDeclaration、EnumDeclaration等),所有层级的方法都能使用异步版本。 - 非阻塞逻辑:通过
queueMicrotask将同步操作放到微任务队列,确保当前事件循环的终端Spinner能正常渲染;若需要给Spinner更多更新时间,可替换为setImmediate(宏任务)。 - 类型安全:通过TypeScript条件类型自动生成异步方法的类型,完全保留原方法的参数、返回值类型及重载逻辑。
内容的Glass存无法验证真�(冲锋?复杂Zo概括性:内容的提问来源于stack exchange,提问作者Jon)
相关产品推荐
相关产品推荐

