问题
Took a look at the declarationEmitter
and for variable declarations, it has the function #emitVariableDeclaration
which eventually calls #writeTypeOfDeclaration
. This code does what is says---it takes a variable declaration and prints the variable and its type---this is exactly what I want to do.
The problem is that when I replicate this code, the VariableDeclaration
node has no symbol property...and thus, the type is always "any". Is there a missing step to initialize "symbols"?
//sample input filecontents
export const foo = '123'
//mycode.js
const ast = ts.createSourceFile(filename, filecontents, ts.ScriptTarget.ES6, true))
const program = ts.createProgram([filename], {});
const typeChecker = program.getDiagnosticsProducingTypeChecker()
const emitResolver = typeChecker.getEmitResolver(filename)
// variableDeclarationNode --- can be obtained using ts.forEachChild and finding node with kind === ts.SyntaxKind.VariableDeclaration
// writer --- an object implementing the SymbolWriter interface that just concatenates to a result string
emitResolver.writeTypeOfDeclaration(variableDeclarationNode, undefined, undefined, writer)
//declarationEmitter.ts
function writeTypeOfDeclaration(
declaration: AccessorDeclaration | VariableLikeDeclaration,
type: TypeNode,
getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
//...
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
}
//`checker.ts`
function writeTypeOfDeclaration(
declaration: AccessorDeclaration | VariableLikeDeclaration,
enclosingDeclaration: Node,
flags: TypeFormatFlags,
writer: SymbolWriter) {
// Get type of the symbol if this is the valid symbol otherwise get type at location
const symbol = getSymbolOfNode(declaration);
const type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
? getTypeOfSymbol(symbol)
: unknownType;
// ....
}
function getMergedSymbol(symbol: Symbol): Symbol {
let merged: Symbol;
return symbol && symbol.mergeId && (merged = mergedSymbols[symbol.mergeId]) ? merged : symbol;
}
function getSymbolOfNode(node: Node): Symbol {
return getMergedSymbol(node.symbol);
}
回答1:
It turns out I was using the wrong AST. In the question, I'm using the AST that doesn't have type. You can get the AST with type injected with the program. The (more) correct solution is:
const program = ts.createProgram(filename, {target: ts.ScriptTarget.ES6, module: ts.ModuleKind.ES6});
const typechecker = program.getDiagnosticsProducingTypeChecker()
const emitResolver = typeChecker.getEmitResolver(filename)))
// THIS IS HOW TO GET AN AST WITH TYPE (Yes, it's called a "SourceFile")
const ast = program.getSourceFile(filename)
// variableDeclarationNode --- can be obtained using ts.forEachChild and finding node with kind === ts.SyntaxKind.VariableDeclaration
// writer --- an object implementing the SymbolWriter interface that just concatenates to a result string
emitResolver.writeTypeOfDeclaration(variableDeclarationNode, undefined, undefined, writer)
回答2:
Is there a missing step to initialize "symbols"?
This is the job of the binder
.
Some docs : https://basarat.gitbooks.io/typescript/content/docs/compiler/binder.html
来源:https://stackoverflow.com/questions/34847471/correct-way-of-getting-type-for-a-variable-declaration-in-a-typescript-ast