I am facing an issue with retrieving the type of a variable using the compiler API. Here is some background information on my situation: Since I execute everything in memory, I have had to create my own compiler host. This is necessary because the typechecker is generated from a 'program' which by default expects files to be written to disk.
In the code sample below, I attempt to determine the types of "input" and "el". I anticipate the output to be "number[]" and "number", respectively. This matches what I would see if I were to hover over them in VSCode.
However, the output that I receive is either "{}" or "any".
I am certain that I am doing something incorrectly or overlooking something, but I cannot seem to identify what it is.
Warm regards, Ike
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));