首页 > 解决方案 > 使用编译器 api 在 typescript 中获取变量的类型

问题描述

我似乎无法使用编译器 API 获取变量的类型。下面是我的示例的一些上下文。由于我在内存中运行所有内容,因此我必须创建自己的编译器主机。这是必需的,因为类型检查器是从“程序”创建的,并且默认情况下需要将文件写入磁盘。

我尝试获取“输入”和“el”的类型。我希望这能打印出“number[]”和“number”。这就像我在 VSCode 中将鼠标悬停在它上面一样。

但是,我得到的输出是“{}”或“any”。

我确定我做错了什么或者我忘记了什么,但我不明白它是什么。

最好的问候,艾克

const code: string = `let input: number[] = [1, 2, 3];
for (let el of input) {
    let x = el * 3;
    if (el > 1) {
        output.push(el);
    }
}`;

const host: ts.CompilerHost = {
  getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
    console.log("getSourceFile", fileName);
    if (fileName === "test.ts") {
        return ts.createSourceFile(fileName, code, languageVersion);
    }
    if (onError) {
        onError("not found");
    }
    // tsc's declarations don't support strict null checks
    return null as any as ts.SourceFile;
  },
  getDefaultLibFileName: () => "", // "lib.d.ts",
  writeFile: (_fileName, _content) => { },
  getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
  getCanonicalFileName: fileName => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(),
  getNewLine: () => ts.sys.newLine,
  useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
  fileExists: (fileName: string) => fileName === "test.ts",
  readFile(fileName: string): string {
    if (fileName === "test.ts") {
      return code;
    }
    return null as any as string;
  },
  resolveModuleNames(_moduleNames: string[], _containingFile: string): ts.ResolvedModule[] {
    throw new Error("unsupported");
  },
  getDirectories(_path: string): string[] {
    throw new Error("unsupported");
  }
};


const program: ts.Program = ts.createProgram(["test.ts"], {allowJs: true}, host);
const checker: ts.TypeChecker = program.getTypeChecker();
const forofke: ts.ForOfStatement = program.getSourceFiles()[0].statements[1];
const stat = forofke.expression;
const type1: ts.Type = checker.getTypeAtLocation(stat);
console.log(checker.typeToString(type1));
const sym: ts.Symbol = checker.getSymbolAtLocation(stat);
const type2: ts.Type = checker.getDeclaredTypeOfSymbol(sym);
console.log(checker.typeToString(type2));
const type3: ts.Type = checker.getTypeOfSymbolAtLocation(sym, stat);
console.log(checker.typeToString(type3));
const type4: ts.Type = checker.getTypeOfSymbolAtLocation(sym, sym.valueDeclaration);
console.log(checker.typeToString(type4));

const stat2 = (<ts.VariableDeclarationList>forofke.initializer).declarations[0].name;
const type12: ts.Type = checker.getTypeAtLocation(stat2);
console.log(checker.typeToString(type12));
const sym2: ts.Symbol = checker.getSymbolAtLocation(stat2);
const type22: ts.Type = checker.getDeclaredTypeOfSymbol(sym2);
console.log(checker.typeToString(type22));
const type32: ts.Type = checker.getTypeOfSymbolAtLocation(sym2, stat2);
console.log(checker.typeToString(type32));
const type42: ts.Type = checker.getTypeOfSymbolAtLocation(sym2, sym2.valueDeclaration);
console.log(checker.typeToString(type42));

标签: typescript

解决方案


我将一个从磁盘加载的“程序”与我的示例中的内存中的一个进行了比较。我注意到从磁盘上'program.getSourceFiles()'中有2个源文件。第二个文件是 lib.d.ts。

我稍微改变了我的样本,现在输出就像我期望的那样。

  getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
    console.log("getSourceFile", fileName);
    if (fileName === "test.ts") {
        return ts.createSourceFile(fileName, code, languageVersion);
    }
    if (fileName === "lib.d.ts") {
        return ts.createSourceFile(fileName, /*READ the file from disk*/, languageVersion);
    }
    if (onError) {
        onError("not found");
    }
    // tsc's declarations don't support strict null checks
    return null as any as ts.SourceFile;
  },
  getDefaultLibFileName: () => "lib.d.ts",

推荐阅读