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.
The AST node to get the symbol for
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.
The symbol to get the type for
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.
The symbol to get the type for
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.).
The symbol to get the declared type for
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.
The symbol to get the name for
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.
The node to get the type for
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.
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.
The type to get properties for
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.
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.).
The type to get signatures for
The kind of signature (Call, Construct, etc.)
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.
The signature to get the return type for
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.
The interface or class type
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.
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.
Optional enclosing declaration for context
Optional formatting flags
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.
Optional enclosing declaration
Optional formatting flags
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.
Optional enclosing declaration
Optional formatting flags
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.
Enclosing declaration for context
flags
NodeBuilderFlags | undefined
required
Node builder flags
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.
The type to make nullable
Flags indicating which nullable types to add (null, undefined)
getNonNullableType()
Removes null and undefined from a type.
The type to make non-nullable
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.
getAliasedSymbol()
Follows all aliases to get the original 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.
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