TypeScript compiler wrapper for static analysis and code manipulation.
—
Direct access to TypeScript's type checker and type information for advanced static analysis and type-aware transformations. This enables sophisticated analysis of TypeScript code beyond syntax-level operations.
The TypeScript type checker provides comprehensive type analysis capabilities.
class TypeChecker {
/** Get the type of a node at its location */
getTypeAtLocation(node: Node): Type;
/** Get the symbol at a specific location */
getSymbolAtLocation(node: Node): Symbol | undefined;
/** Get the type of a symbol at a specific location */
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
/** Get the apparent type (after applying type arguments) */
getApparentType(type: Type): Type;
/** Get the base type of a type */
getBaseTypeOfLiteralType(type: Type): Type;
/** Get the full type of a node (including contextual type) */
getFullTypeAtLocation(node: Node): Type;
/** Get the contextual type for an expression */
getContextualType(node: Expression): Type | undefined;
/** Get the signature from a declaration */
getSignatureFromDeclaration(node: SignatureDeclaration): Signature | undefined;
/** Get all signatures for a type */
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
/** Get the return type of a signature */
getReturnTypeOfSignature(signature: Signature): Type;
/** Check if types are assignable */
isTypeAssignableTo(source: Type, target: Type): boolean;
/** Get exports of a module */
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
/** Get properties of a type */
getPropertiesOfType(type: Type): Symbol[];
/** Get all accessible symbols at location */
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
}
enum SignatureKind {
Call = 0,
Construct = 1,
}Represents a TypeScript type with comprehensive type information and analysis methods.
class Type {
/** Get the string representation of the type */
getText(enclosingNode?: Node, typeFormatFlags?: TypeFormatFlags): string;
/** Get the symbol associated with this type */
getSymbol(): Symbol | undefined;
/** Get the apparent type (after type argument substitution) */
getApparentType(): Type;
/** Get constraint of a type parameter */
getConstraint(): Type | undefined;
/** Get default type of a type parameter */
getDefault(): Type | undefined;
/** Get union types if this is a union type */
getUnionTypes(): Type[];
/** Get intersection types if this is an intersection type */
getIntersectionTypes(): Type[];
/** Get type arguments if this is a generic type instance */
getTypeArguments(): Type[];
/** Get call signatures */
getCallSignatures(): Signature[];
/** Get construct signatures */
getConstructSignatures(): Signature[];
/** Get array element type if this is an array type */
getArrayElementType(): Type | undefined;
/** Get number index type */
getNumberIndexType(): Type | undefined;
/** Get string index type */
getStringIndexType(): Type | undefined;
/** Get base types */
getBaseTypes(): Type[];
/** Check if this is an array type */
isArray(): boolean;
/** Check if this is a boolean type */
isBoolean(): boolean;
/** Check if this is a string type */
isString(): boolean;
/** Check if this is a number type */
isNumber(): boolean;
/** Check if this is a literal type */
isLiteral(): boolean;
/** Check if this is a boolean literal type */
isBooleanLiteral(): boolean;
/** Check if this is an enum literal type */
isEnumLiteral(): boolean;
/** Check if this is a number literal type */
isNumberLiteral(): boolean;
/** Check if this is a string literal type */
isStringLiteral(): boolean;
/** Check if this is a class type */
isClass(): boolean;
/** Check if this is a class or interface type */
isClassOrInterface(): boolean;
/** Check if this is an enum type */
isEnum(): boolean;
/** Check if this is an interface type */
isInterface(): boolean;
/** Check if this is an object type */
isObject(): boolean;
/** Check if this is a type parameter */
isTypeParameter(): boolean;
/** Check if this is a union type */
isUnion(): boolean;
/** Check if this is an intersection type */
isIntersection(): boolean;
/** Check if this is an anonymous type */
isAnonymous(): boolean;
/** Check if this is null */
isNull(): boolean;
/** Check if this is undefined */
isUndefined(): boolean;
/** Check if this is never */
isNever(): boolean;
/** Check if this is unknown */
isUnknown(): boolean;
/** Check if this is any */
isAny(): boolean;
/** Get literal value for literal types */
getLiteralValue(): string | number | boolean | undefined;
/** Get properties of this type */
getProperties(): Symbol[];
/** Get property by name */
getProperty(name: string): Symbol | undefined;
/** Get non-nullable type (removes null and undefined) */
getNonNullableType(): Type;
}Represents a TypeScript symbol with name, declarations, and type information.
class Symbol {
/** Get the symbol name */
getName(): string;
/** Get the escaped name */
getEscapedName(): string;
/** Get all declarations of this symbol */
getDeclarations(): Node[];
/** Get first declaration */
getFirstDeclaration(): Node | undefined;
/** Get value declaration (for symbols that have values) */
getValueDeclaration(): Node | undefined;
/** Get type declaration (for type symbols) */
getTypeDeclaration(): Node | undefined;
/** Get the symbol flags */
getFlags(): SymbolFlags;
/** Get exports if this is a module or namespace */
getExports(): Symbol[];
/** Get global exports */
getGlobalExports(): Symbol[];
/** Get members if this is a class or interface */
getMembers(): Symbol[];
/** Get the type of this symbol */
getTypeAtLocation(location: Node): Type;
/** Get documentation comment */
getDocumentationComment(): SymbolDisplayPart[];
/** Get JSDoc tags */
getJsDocTags(): JSDocTagInfo[];
/** Check if symbol has specific flag */
hasFlag(flag: SymbolFlags): boolean;
/** Check if symbol is optional */
isOptional(): boolean;
}Represents a function or method signature with parameter and return type information.
class Signature {
/** Get parameters of this signature */
getParameters(): Symbol[];
/** Get return type */
getReturnType(): Type;
/** Get type parameters */
getTypeParameters(): TypeParameter[];
/** Get the declaration associated with this signature */
getDeclaration(): SignatureDeclaration | undefined;
/** Get documentation comment */
getDocumentationComment(): SymbolDisplayPart[];
/** Get JSDoc tags */
getJsDocTags(): JSDocTagInfo[];
/** Get signature string representation */
getText(): string;
}
class TypeParameter extends Type {
/** Get the constraint of this type parameter */
getConstraint(): Type | undefined;
/** Get the default type of this type parameter */
getDefault(): Type | undefined;
}TypeScript diagnostic information for errors, warnings, and suggestions.
class Diagnostic {
/** Get the diagnostic message text */
getMessageText(): string;
/** Get the source file where this diagnostic occurred */
getSourceFile(): SourceFile | undefined;
/** Get the start position */
getStart(): number | undefined;
/** Get the length */
getLength(): number | undefined;
/** Get the end position */
getEnd(): number | undefined;
/** Get diagnostic category */
getCategory(): DiagnosticCategory;
/** Get diagnostic code */
getCode(): number;
/** Get the line number (1-indexed) */
getLineNumber(): number | undefined;
}
interface SymbolDisplayPart {
text: string;
kind: string;
}
interface JSDocTagInfo {
name: string;
text?: SymbolDisplayPart[];
}TypeScript language service providing IDE-like functionality.
class LanguageService {
/** Get completions at a position */
getCompletionsAtPosition(fileName: string, position: number): CompletionInfo | undefined;
/** Get quick info at a position */
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
/** Get definition at a position */
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
/** Get type definition at a position */
getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
/** Get references at a position */
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[];
/** Get semantic diagnostics */
getSemanticDiagnostics(fileName: string): Diagnostic[];
/** Get syntactic diagnostics */
getSyntacticDiagnostics(fileName: string): Diagnostic[];
/** Get suggestion diagnostics */
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
/** Find all references */
findReferences(fileName: string, position: number): ReferencedSymbol[];
/** Get rename info */
getRenameInfo(fileName: string, position: number): RenameInfo;
/** Find rename locations */
findRenameLocations(fileName: string, position: number, findInStrings?: boolean, findInComments?: boolean): RenameLocation[];
}
interface CompletionInfo {
entries: CompletionEntry[];
isGlobalCompletion: boolean;
isMemberCompletion: boolean;
isNewIdentifierLocation: boolean;
}
interface CompletionEntry {
name: string;
kind: string;
kindModifiers?: string;
sortText: string;
insertText?: string;
replacementSpan?: TextSpan;
}
interface QuickInfo {
kind: string;
kindModifiers: string;
textSpan: TextSpan;
displayParts?: SymbolDisplayPart[];
documentation?: SymbolDisplayPart[];
tags?: JSDocTagInfo[];
}
interface DefinitionInfo {
fileName: string;
textSpan: TextSpan;
kind: string;
name: string;
containerKind: string;
containerName: string;
}
interface TextSpan {
start: number;
length: number;
}Usage Examples:
import { Project, SyntaxKind } from "ts-morph";
const project = new Project({
tsConfigFilePath: "tsconfig.json",
});
const sourceFile = project.createSourceFile("analysis.ts", `
interface User {
id: number;
name: string;
email?: string;
}
class UserService {
private users: User[] = [];
async getUser(id: number): Promise<User | undefined> {
return this.users.find(user => user.id === id);
}
}
const service = new UserService();
const user = service.getUser(1);
`);
const typeChecker = project.getTypeChecker();
// Analyze types
const userInterface = sourceFile.getInterfaceOrThrow("User");
const userType = typeChecker.getTypeAtLocation(userInterface);
console.log("User type text:", userType.getText());
console.log("Is User an object type:", userType.isObject());
// Get properties of User interface
const properties = userType.getProperties();
properties.forEach(prop => {
const propType = typeChecker.getTypeOfSymbolAtLocation(prop, userInterface);
console.log(\`Property \${prop.getName()}: \${propType.getText()}\`);
console.log(\`Is optional: \${prop.isOptional()}\`);
});
// Analyze method return types
const userServiceClass = sourceFile.getClassOrThrow("UserService");
const getUserMethod = userServiceClass.getMethodOrThrow("getUser");
const signature = typeChecker.getSignatureFromDeclaration(getUserMethod);
if (signature) {
const returnType = signature.getReturnType();
console.log("getUser return type:", returnType.getText());
console.log("Is Promise:", returnType.getText().startsWith("Promise"));
// Get the actual type inside Promise
const typeArgs = returnType.getTypeArguments();
if (typeArgs.length > 0) {
console.log("Promise type argument:", typeArgs[0].getText());
}
}
// Analyze variable types
const serviceVariable = sourceFile.getVariableDeclarationOrThrow("service");
const serviceType = typeChecker.getTypeAtLocation(serviceVariable);
console.log("Service variable type:", serviceType.getText());
// Find all number literal types
const numberLiterals = sourceFile.getDescendantsOfKind(SyntaxKind.NumericLiteral);
numberLiterals.forEach(literal => {
const type = typeChecker.getTypeAtLocation(literal);
console.log(\`Number literal \${literal.getText()} has type: \${type.getText()}\`);
console.log("Is number literal type:", type.isNumberLiteral());
if (type.isNumberLiteral()) {
console.log("Literal value:", type.getLiteralValue());
}
});
// Check type assignability
const numberType = typeChecker.getTypeAtLocation(
sourceFile.getFirstDescendantByKindOrThrow(SyntaxKind.NumericLiteral)
);
const stringType = typeChecker.getTypeAtLocation(
sourceFile.addVariableStatement({
declarationKind: "const",
declarations: [{ name: "temp", initializer: "'hello'" }]
}).getDeclarations()[0]
);
console.log("Can assign string to number:",
typeChecker.isTypeAssignableTo(stringType, numberType));Advanced Type Analysis:
import { Project } from "ts-morph";
const project = new Project();
const sourceFile = project.createSourceFile("advanced.ts", `
type EventHandler<T> = (event: T) => void;
interface ClickEvent {
type: 'click';
x: number;
y: number;
}
interface KeyEvent {
type: 'key';
key: string;
code: number;
}
type AllEvents = ClickEvent | KeyEvent;
class EventEmitter {
private handlers: Map<string, EventHandler<any>[]> = new Map();
on<T extends AllEvents>(type: T['type'], handler: EventHandler<T>): void {
// Implementation
}
}
`);
const typeChecker = project.getTypeChecker();
// Analyze generic types
const eventHandlerType = sourceFile.getTypeAliasOrThrow("EventHandler");
const handlerType = typeChecker.getTypeAtLocation(eventHandlerType);
console.log("EventHandler type:", handlerType.getText());
// Analyze union types
const allEventsType = sourceFile.getTypeAliasOrThrow("AllEvents");
const unionType = typeChecker.getTypeAtLocation(allEventsType);
console.log("AllEvents is union:", unionType.isUnion());
if (unionType.isUnion()) {
const unionTypes = unionType.getUnionTypes();
unionTypes.forEach((type, index) => {
console.log(\`Union member \${index}: \${type.getText()}\`);
// Analyze each union member's properties
const properties = type.getProperties();
properties.forEach(prop => {
const propType = typeChecker.getTypeOfSymbolAtLocation(prop, allEventsType);
console.log(\` Property \${prop.getName()}: \${propType.getText()}\`);
});
});
}
// Analyze generic method constraints
const eventEmitterClass = sourceFile.getClassOrThrow("EventEmitter");
const onMethod = eventEmitterClass.getMethodOrThrow("on");
const onSignature = typeChecker.getSignatureFromDeclaration(onMethod);
if (onSignature) {
const typeParams = onSignature.getTypeParameters();
typeParams.forEach(typeParam => {
console.log("Type parameter:", typeParam.getText());
const constraint = typeParam.getConstraint();
if (constraint) {
console.log("Constraint:", constraint.getText());
}
});
}Install with Tessl CLI
npx tessl i tessl/npm-ts-morph