求助:如何利用TypeScript编译器API实现类型推断函数inferType?
使用TypeScript Compiler API实现类型推断函数
当然有可行的实现方法!咱们可以借助TypeScript Compiler API的类型检查能力来完成这个需求。下面是具体的实现思路和代码示例:
核心思路
- 先创建一个TypeScript程序实例,用来解析和检查包含目标变量的临时代码
- 定位到目标变量/函数对应的语法节点,获取它的符号(Symbol)和类型(Type)
- 利用TypeScript内置的类型格式化工具,将类型对象转换为字符串形式
完整代码实现
import * as ts from 'typescript'; function inferType(target: unknown): string { // 处理函数的特殊情况:直接传入函数的话,JSON.stringify会丢失函数体,所以单独处理 let code: string; if (typeof target === 'function') { // 提取函数的源码(注意:这个方式在常规开发场景可用,压缩后的代码可能受限) code = `const target = ${target.toString()};`; } else { // 普通变量用JSON.stringify嵌入到临时代码中 code = `const target = ${JSON.stringify(target)};`; } // 创建临时源文件 const sourceFile = ts.createSourceFile( 'temp.ts', code, ts.ScriptTarget.Latest, true ); // 创建TypeScript程序实例,启用严格模式确保类型推断准确 const program = ts.createProgram({ rootNames: ['temp.ts'], options: { strict: true } }); const checker = program.getTypeChecker(); // 找到目标变量的声明节点 const targetDecl = sourceFile.statements.find( ts.isVariableStatement )?.declarations[0]; if (!targetDecl) throw new Error('无法定位目标变量的声明'); // 获取变量对应的符号和类型 const symbol = checker.getSymbolAtLocation(targetDecl.name); if (!symbol) throw new Error('无法获取目标变量的类型符号'); const type = checker.getTypeOfSymbolAtLocation(symbol, targetDecl.name); // 将类型转换为字符串,去掉参数名以匹配示例格式 return checker.typeToString( type, undefined, ts.TypeFormatFlags.NoParameterNames ); } // 测试示例 let bar = [1, 2, 3]; let bar2 = 5; function foo(a: number[], b: number) { return a[0] + b; } console.log(inferType(bar)); // 输出 "number[]" console.log(inferType(bar2)); // 输出 "number" console.log(inferType(foo)); // 输出 "(number[], number) => number"
关键细节说明
- 临时源文件的作用:TypeScript Compiler API是基于源码进行类型分析的,所以我们需要把目标变量/函数嵌入到一段临时代码中,让编译器能正确解析它的上下文和类型
- 函数的特殊处理:普通变量可以用
JSON.stringify序列化,但函数不行,所以我们直接用toString()提取函数的源码(常规开发场景足够用,压缩混淆后的代码可能失效) - 类型格式化选项:
ts.TypeFormatFlags.NoParameterNames这个选项可以让类型字符串去掉参数名,正好匹配你示例中(number[], number) => number的格式;如果需要保留参数名,去掉这个选项即可 - 类型检查器(TypeChecker):这是整个实现的核心,它提供了获取类型、解析符号、格式化类型等一系列API,是Compiler API中处理类型相关逻辑的关键工具
内容的提问来源于stack exchange,提问作者benjaminz
相关产品推荐
相关产品推荐

