Skip to main content

Overview

The TypeChecker is the semantic analysis engine of the TypeScript Compiler API. It provides methods to query type information, resolve symbols, and perform type-related operations on the Abstract Syntax Tree (AST).

Getting a TypeChecker

The TypeChecker is obtained from a Program instance:
import * as ts from 'typescript';

const program = ts.createProgram(['./src/index.ts'], {
  target: ts.ScriptTarget.ES2020
});

const typeChecker = program.getTypeChecker();

Symbol Methods

getSymbolAtLocation()

Returns the symbol for a node at a specific location.
node
Node
required
The AST node to get the symbol for
return
Symbol | undefined
The symbol at the location, or undefined if not found
const sourceFile = program.getSourceFile('./src/index.ts');
if (sourceFile) {
  ts.forEachChild(sourceFile, (node) => {
    if (ts.isIdentifier(node)) {
      const symbol = typeChecker.getSymbolAtLocation(node);
      if (symbol) {
        console.log(`Found symbol: ${symbol.name}`);
      }
    }
  });
}

getTypeOfSymbolAtLocation()

Returns the type of a symbol at a specific location.
symbol
Symbol
required
The symbol to get the type for
node
Node
required
The location node
return
Type
The type of the symbol at that location
if (ts.isFunctionDeclaration(node) && node.name) {
  const symbol = typeChecker.getSymbolAtLocation(node.name);
  if (symbol) {
    const type = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
    console.log(`Function type: ${typeChecker.typeToString(type)}`);
  }
}

getTypeOfSymbol()

Returns the type of a symbol.
symbol
Symbol
required
The symbol to get the type for
return
Type
The type of the symbol
const symbol = typeChecker.getSymbolAtLocation(identifier);
if (symbol) {
  const type = typeChecker.getTypeOfSymbol(symbol);
  console.log(typeChecker.typeToString(type));
}

getDeclaredTypeOfSymbol()

Returns the declared type of a symbol (for classes, interfaces, etc.).
symbol
Symbol
required
The symbol to get the declared type for
return
Type
The declared type of the symbol
if (ts.isClassDeclaration(node) && node.name) {
  const symbol = typeChecker.getSymbolAtLocation(node.name);
  if (symbol) {
    const type = typeChecker.getDeclaredTypeOfSymbol(symbol);
    console.log(`Class type: ${typeChecker.typeToString(type)}`);
  }
}

getFullyQualifiedName()

Returns the fully qualified name of a symbol.
symbol
Symbol
required
The symbol to get the name for
return
string
The fully qualified name
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
  const fullyQualifiedName = typeChecker.getFullyQualifiedName(symbol);
  console.log(`Fully qualified: ${fullyQualifiedName}`);
}

Type Methods

getTypeAtLocation()

Returns the type of an expression at a specific location.
node
Node
required
The node to get the type for
return
Type
The type at the location
if (ts.isVariableDeclaration(node) && node.initializer) {
  const type = typeChecker.getTypeAtLocation(node.initializer);
  console.log(`Initializer type: ${typeChecker.typeToString(type)}`);
}

getTypeFromTypeNode()

Converts a type node to a Type object.
node
TypeNode
required
The type node to convert
return
Type
The Type object
if (ts.isVariableDeclaration(node) && node.type) {
  const type = typeChecker.getTypeFromTypeNode(node.type);
  console.log(`Declared type: ${typeChecker.typeToString(type)}`);
}

getPropertiesOfType()

Returns all properties of a type.
type
Type
required
The type to get properties for
return
Symbol[]
Array of property symbols
const type = typeChecker.getTypeAtLocation(node);
const properties = typeChecker.getPropertiesOfType(type);
properties.forEach(prop => {
  console.log(`Property: ${prop.name}`);
});

getPropertyOfType()

Returns a specific property of a type by name.
type
Type
required
The type to search
propertyName
string
required
The name of the property
return
Symbol | undefined
The property symbol, or undefined if not found
const type = typeChecker.getTypeAtLocation(objectNode);
const lengthProp = typeChecker.getPropertyOfType(type, 'length');
if (lengthProp) {
  console.log('Has length property');
}

getSignaturesOfType()

Returns all signatures of a type (for functions, constructors, etc.).
type
Type
required
The type to get signatures for
kind
SignatureKind
required
The kind of signature (Call, Construct, etc.)
return
readonly Signature[]
Array of signatures
const type = typeChecker.getTypeAtLocation(functionNode);
const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
signatures.forEach(sig => {
  const sigString = typeChecker.signatureToString(sig);
  console.log(`Signature: ${sigString}`);
});

getReturnTypeOfSignature()

Returns the return type of a signature.
signature
Signature
required
The signature to get the return type for
return
Type
The return type
const type = typeChecker.getTypeAtLocation(functionNode);
const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
if (signatures.length > 0) {
  const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
  console.log(`Returns: ${typeChecker.typeToString(returnType)}`);
}

getBaseTypes()

Returns the base types of a class or interface.
type
InterfaceType
required
The interface or class type
return
BaseType[]
Array of base types
if (ts.isClassDeclaration(node) && node.name) {
  const symbol = typeChecker.getSymbolAtLocation(node.name);
  if (symbol) {
    const type = typeChecker.getDeclaredTypeOfSymbol(symbol) as ts.InterfaceType;
    const baseTypes = typeChecker.getBaseTypes(type);
    baseTypes.forEach(baseType => {
      console.log(`Extends: ${typeChecker.typeToString(baseType)}`);
    });
  }
}

getTypeArguments()

Returns the type arguments for a type reference.
type
TypeReference
required
The type reference
return
readonly Type[]
Array of type arguments
const type = typeChecker.getTypeAtLocation(node) as ts.TypeReference;
if (typeChecker.isTypeReference(type)) {
  const typeArgs = typeChecker.getTypeArguments(type);
  typeArgs.forEach(arg => {
    console.log(`Type arg: ${typeChecker.typeToString(arg)}`);
  });
}

Type Conversion Methods

typeToString()

Converts a type to a string representation.
type
Type
required
The type to convert
enclosingDeclaration
Node
Optional enclosing declaration for context
flags
TypeFormatFlags
Optional formatting flags
return
string
String representation of the type
const type = typeChecker.getTypeAtLocation(node);
const typeString = typeChecker.typeToString(type);
console.log(`Type: ${typeString}`);

// With flags for more detailed output
const detailedString = typeChecker.typeToString(
  type,
  undefined,
  ts.TypeFormatFlags.NoTruncation
);

symbolToString()

Converts a symbol to a string representation.
symbol
Symbol
required
The symbol to convert
enclosingDeclaration
Node
Optional enclosing declaration
meaning
SymbolFlags
Optional meaning flags
flags
SymbolFormatFlags
Optional formatting flags
return
string
String representation of the symbol
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
  const symbolString = typeChecker.symbolToString(symbol);
  console.log(`Symbol: ${symbolString}`);
}

signatureToString()

Converts a signature to a string representation.
signature
Signature
required
The signature to convert
enclosingDeclaration
Node
Optional enclosing declaration
flags
TypeFormatFlags
Optional formatting flags
kind
SignatureKind
Optional signature kind
return
string
String representation of the signature
const type = typeChecker.getTypeAtLocation(functionNode);
const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
if (signatures.length > 0) {
  const sigString = typeChecker.signatureToString(signatures[0]);
  console.log(`Signature: ${sigString}`);
}

typeToTypeNode()

Converts a Type to a TypeNode AST node.
type
Type
required
The type to convert
enclosingDeclaration
Node | undefined
required
Enclosing declaration for context
flags
NodeBuilderFlags | undefined
required
Node builder flags
return
TypeNode | undefined
The TypeNode AST node
const type = typeChecker.getTypeAtLocation(node);
const typeNode = typeChecker.typeToTypeNode(
  type,
  undefined,
  ts.NodeBuilderFlags.None
);
if (typeNode) {
  console.log(`TypeNode kind: ${ts.SyntaxKind[typeNode.kind]}`);
}

Utility Methods

getNullableType()

Returns a nullable version of a type.
type
Type
required
The type to make nullable
flags
TypeFlags
required
Flags indicating which nullable types to add (null, undefined)
return
Type
The nullable type

getNonNullableType()

Removes null and undefined from a type.
type
Type
required
The type to make non-nullable
return
Type
The non-nullable type
const type = typeChecker.getTypeAtLocation(node);
const nonNullable = typeChecker.getNonNullableType(type);
console.log(`Non-nullable: ${typeChecker.typeToString(nonNullable)}`);

getWidenedType()

Returns a widened version of a type.
type
Type
required
The type to widen
return
Type
The widened type

getAliasedSymbol()

Follows all aliases to get the original symbol.
symbol
Symbol
required
The symbol to resolve
return
Symbol
The original aliased symbol
const symbol = typeChecker.getSymbolAtLocation(importNode);
if (symbol) {
  const aliasedSymbol = typeChecker.getAliasedSymbol(symbol);
  console.log(`Original: ${aliasedSymbol.name}`);
}

getExportSymbolOfSymbol()

Returns the exported symbol for a local symbol.
symbol
Symbol
required
The local symbol
return
Symbol
The exported symbol

Primitive Type Getters

const anyType = typeChecker.getAnyType();
const stringType = typeChecker.getStringType();
const numberType = typeChecker.getNumberType();
const booleanType = typeChecker.getBooleanType();
const voidType = typeChecker.getVoidType();
const undefinedType = typeChecker.getUndefinedType();
const unknownType = typeChecker.getUnknownType();
const bigIntType = typeChecker.getBigIntType();

// Literal types
const helloType = typeChecker.getStringLiteralType('hello');
const fortyTwoType = typeChecker.getNumberLiteralType(42);
const trueType = typeChecker.getTrueType();
const falseType = typeChecker.getFalseType();

Complete Example

import * as ts from 'typescript';

function analyzeSourceFile(fileName: string) {
  const program = ts.createProgram([fileName], {
    target: ts.ScriptTarget.ES2020
  });
  
  const typeChecker = program.getTypeChecker();
  const sourceFile = program.getSourceFile(fileName);
  
  if (!sourceFile) {
    console.error('File not found');
    return;
  }
  
  function visit(node: ts.Node) {
    // Analyze function declarations
    if (ts.isFunctionDeclaration(node) && node.name) {
      const symbol = typeChecker.getSymbolAtLocation(node.name);
      if (symbol) {
        console.log(`\nFunction: ${symbol.name}`);
        
        const type = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
        const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
        
        signatures.forEach(sig => {
          const returnType = typeChecker.getReturnTypeOfSignature(sig);
          console.log(`  Returns: ${typeChecker.typeToString(returnType)}`);
          console.log(`  Signature: ${typeChecker.signatureToString(sig)}`);
        });
      }
    }
    
    // Analyze variable declarations
    if (ts.isVariableDeclaration(node) && node.name) {
      const symbol = typeChecker.getSymbolAtLocation(node.name);
      if (symbol) {
        const type = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
        console.log(`\nVariable: ${symbol.name}`);
        console.log(`  Type: ${typeChecker.typeToString(type)}`);
      }
    }
    
    // Analyze class declarations
    if (ts.isClassDeclaration(node) && node.name) {
      const symbol = typeChecker.getSymbolAtLocation(node.name);
      if (symbol) {
        console.log(`\nClass: ${symbol.name}`);
        
        const type = typeChecker.getDeclaredTypeOfSymbol(symbol) as ts.InterfaceType;
        const properties = typeChecker.getPropertiesOfType(type);
        
        console.log('  Properties:');
        properties.forEach(prop => {
          const propType = typeChecker.getTypeOfSymbolAtLocation(prop, node);
          console.log(`    ${prop.name}: ${typeChecker.typeToString(propType)}`);
        });
        
        const baseTypes = typeChecker.getBaseTypes(type);
        if (baseTypes.length > 0) {
          console.log('  Extends:');
          baseTypes.forEach(base => {
            console.log(`    ${typeChecker.typeToString(base)}`);
          });
        }
      }
    }
    
    ts.forEachChild(node, visit);
  }
  
  visit(sourceFile);
}

analyzeSourceFile('./src/index.ts');

See Also

Build docs developers (and LLMs) love