如何从程序化创建的TypeScript AST生成.d.ts类型定义文件?
从TypeScript AST生成.d.ts类型定义文件的方法与示例
问题1:是否存在从AST生成.d.ts的方法?
当然有!TypeScript Compiler API本身就提供了完整的能力,能把你构建的AST转换为.d.ts声明文件。核心思路是通过配置特定编译选项,让编译器在输出阶段生成声明文件而非普通JavaScript文件。
关键要注意这几个核心步骤:
- 把你构建的AST节点包装进
SourceFile实例(这是TypeScript程序的基础组成单元) - 创建
Program实例时,开启declaration: true编译选项;如果只想生成声明文件,再加emitDeclarationOnly: true可以跳过JS文件生成,提升效率 - 调用
ts.emit方法触发编译,就能直接获取生成的.d.ts内容,或者让编译器自动写入磁盘
问题2:相关示例
下面是一个完整的实操示例,展示如何构建一个简单的函数声明AST,并生成对应的.d.ts文件:
import * as ts from "typescript"; // 1. 构建AST节点:创建一个接收string参数、返回string的greet函数 const greetFunction = ts.factory.createFunctionDeclaration( undefined, // 修饰符(比如export) undefined, // 类型参数 "greet", // 函数名称 undefined, // 参数类型参数 [ ts.factory.createParameterDeclaration( undefined, undefined, "name", undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), // 返回类型 ts.factory.createBlock([ ts.factory.createReturnStatement( ts.factory.createTemplateExpression( ts.factory.createTemplateHead("Hello, "), [ ts.factory.createTemplateSpan( ts.factory.createIdentifier("name"), ts.factory.createTemplateTail("!") ) ] ) ) ]) ); // 2. 将函数节点包装进SourceFile(TypeScript程序的最小单元) const sourceFile = ts.factory.createSourceFile( [greetFunction], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None ); // 3. 配置编译选项:开启声明文件生成,仅输出声明 const compilerOptions: ts.CompilerOptions = { declaration: true, emitDeclarationOnly: true, outDir: "./dist", // 可选,指定声明文件输出目录 target: ts.ScriptTarget.ESNext }; // 4. 创建Program实例,自定义宿主处理内存中的AST const program = ts.createProgram({ rootNames: [], // 因为用的是内存SourceFile,所以rootNames为空 options: compilerOptions, host: { getSourceFile: (fileName, languageVersion) => { if (fileName === "virtual.ts") return sourceFile; return undefined; }, writeFile: (fileName, content) => { // 这里可以处理生成的内容:打印到控制台或写入磁盘 console.log(`生成的${fileName}内容:\n${content}`); // 若要写入磁盘,可使用fs.writeFileSync(fileName, content) }, getDefaultLibFileName: () => ts.getDefaultLibFilePath(compilerOptions), useCaseSensitiveFileNames: () => false, getCanonicalFileName: (fileName) => fileName, getCurrentDirectory: () => process.cwd(), getNewLine: () => "\n", fileExists: (fileName) => fileName === "virtual.ts", readFile: () => "" } }); // 5. 触发emit,生成.d.ts文件 const emitResult = program.emit(); // 检查生成过程是否有错误 if (emitResult.emitSkipped) { console.error("生成声明文件时出错:"); const diagnostics = ts.getPreEmitDiagnostics(program); diagnostics.forEach(d => { console.error(ts.flattenDiagnosticMessageText(d.messageText, "\n")); }); } else { console.log("声明文件生成成功!"); }
运行这段代码后,控制台会输出类似这样的.d.ts内容:
declare function greet(name: string): string;
如果配置了outDir,文件会自动写入./dist/virtual.d.ts路径下。
内容的提问来源于stack exchange,提问作者Jonas Rabbe
相关产品推荐
相关产品推荐

