CodeBlanks Logo Icon CodeBlanks

Symbol resolution

Learn declaration resolution with Symbol.

Symbol resolution

Symbol resolution is finding which declaration an identifier refers to. checker.getSymbolAtLocation(node) returns a Symbol | undefined for an Identifier node. The symbol carries the declaration's name and its declaration list.

const sym = checker.getSymbolAtLocation(id);
if (sym) {
  console.log(sym.getName());
  console.log(sym.declarations?.length);
}

Symbol and declarations

A symbol's .declarations property is an array of all declarations of that symbol. Most cases have a single declaration, but function overloads can have several. symbol.getName() returns the declaration's name.

const sym = checker.getSymbolAtLocation(node.name);
console.log(sym?.declarations?.length); // 1
console.log(sym?.getName()); // "topla"

Practice Resolve the function symbol

Create an in-memory program from function topla(a: number, b: number): number { return a + b; } with noLib: true. Obtain the TypeChecker, write a visit function that resolves the symbol of each FunctionDeclaration's name with getSymbolAtLocation and prints name: declarationCount. Walk with ts.forEachChild.

Starter code

index.ts
import * as ts from "typescript";

// Kaynak: function topla(a: number, b: number): number { return a + b; }
// host ve program oluştur (noLib: true)
// TypeChecker al
// visit fonksiyonu yaz: FunctionDeclaration bulunca sembolünü çöz
// ad: tanımSayisi biçiminde yazdır
// forEachChild ile gez

// kodunu buraya yaz

Sample solution

index.ts
import ts from "typescript";

const fileName = "app.ts";
const sourceText = "function topla(a: number, b: number): number { return a + b; }";

const host: ts.CompilerHost = {
  fileExists: (n) => n === fileName,
  readFile: (n) => (n === fileName ? sourceText : undefined),
  getSourceFile: (n, lang) =>
    n === fileName ? ts.createSourceFile(n, sourceText, lang, true) : undefined,
  writeFile: () => {},
  getDefaultLibFileName: () => "lib.d.ts",
  useCaseSensitiveFileNames: () => true,
  getCanonicalFileName: (n) => n,
  getCurrentDirectory: () => "",
  getNewLine: () => "\n",
};

const program = ts.createProgram([fileName], { noLib: true }, host);
const checker = program.getTypeChecker();
const sf = program.getSourceFile(fileName)!;

function visit(node: ts.Node) {
  if (ts.isFunctionDeclaration(node) && node.name) {
    const sym = checker.getSymbolAtLocation(node.name);
    console.log(`${sym?.getName()}: ${sym?.declarations?.length}`);
  }
  ts.forEachChild(node, visit);
}
visit(sf);

Expected output

topla: 1

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does checker.getSymbolAtLocation(id) return?

  • string
  • Type
  • Symbol | undefined Correct answer
  • Declaration[]

Explanation: getSymbolAtLocation returns Symbol | undefined for an Identifier; undefined when there is no declaration. It does not directly return a string, Type or Declaration[].

2 Declaration count

Question
const sym = checker.getSymbolAtLocation(node.name);
console.log(sym?.____?.length);
Answer
const sym = checker.getSymbolAtLocation(node.name);
console.log(sym?.declarations?.length);

Explanation: Symbol.declarations returns a Declaration[]; there is no getDeclarations method, declarationList is specific to VariableDeclaration, and nodes is not a general property.

3 Symbol resolution parts

Term Meaning
checker.getSymbolAtLocation Gives Symbol for an Identifier
symbol.getName() Returns the declaration name
symbol.declarations Gives the declaration array
TypeChecker Resolves symbols and types

All lessons in Expert