TypeScript compiler wrapper for static analysis and code manipulation.
—
Structure-based API for creating new TypeScript code elements with full type safety and intelligent formatting. The structure system provides a declarative way to generate code without manually constructing AST nodes.
Base interfaces that define the shape of code elements to be generated.
enum StructureKind {
ImportAttribute,
CallSignature,
Class,
ClassStaticBlock,
ConstructSignature,
Constructor,
ConstructorOverload,
Decorator,
Enum,
EnumMember,
ExportAssignment,
ExportDeclaration,
ExportSpecifier,
Function,
FunctionOverload,
GetAccessor,
ImportDeclaration,
ImportSpecifier,
IndexSignature,
Interface,
JsxAttribute,
JsxSpreadAttribute,
JsxElement,
JsxSelfClosingElement,
JSDoc,
JSDocTag,
Method,
MethodOverload,
MethodSignature,
Module,
Parameter,
Property,
PropertyAssignment,
PropertySignature,
SetAccessor,
ShorthandPropertyAssignment,
SourceFile,
SpreadAssignment,
TypeAlias,
TypeParameter,
VariableDeclaration,
VariableStatement,
}
interface Structure {
kind: StructureKind;
}
interface StatementedNodeStructure {
statements?: (string | WriterFunction | StatementStructures)[];
}
interface JSDocableNodeStructure {
docs?: (JSDocStructure | string)[];
}
interface DecoratableNodeStructure {
decorators?: DecoratorStructure[];
}Structures for generating class-related code elements.
interface ClassDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
kind: StructureKind.Class;
name: string;
extends?: string;
implements?: string[];
typeParameters?: TypeParameterDeclarationStructure[];
isAbstract?: boolean;
isExported?: boolean;
isDefaultExport?: boolean;
constructors?: ConstructorDeclarationStructure[];
properties?: PropertyDeclarationStructure[];
methods?: MethodDeclarationStructure[];
getAccessors?: GetAccessorDeclarationStructure[];
setAccessors?: SetAccessorDeclarationStructure[];
}
interface PropertyDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
kind: StructureKind.Property;
name: string;
type?: string;
initializer?: string | WriterFunction;
hasQuestionToken?: boolean;
hasExclamationToken?: boolean;
isReadonly?: boolean;
isStatic?: boolean;
scope?: Scope;
}
interface MethodDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
kind: StructureKind.Method;
name: string;
parameters?: ParameterDeclarationStructure[];
returnType?: string;
typeParameters?: TypeParameterDeclarationStructure[];
statements?: (string | WriterFunction)[];
isAbstract?: boolean;
isAsync?: boolean;
isGenerator?: boolean;
isStatic?: boolean;
scope?: Scope;
overloads?: MethodDeclarationOverloadStructure[];
}
interface ConstructorDeclarationStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.Constructor;
parameters?: ParameterDeclarationStructure[];
statements?: (string | WriterFunction)[];
scope?: Scope;
overloads?: ConstructorDeclarationOverloadStructure[];
}
enum Scope {
Public = "public",
Protected = "protected",
Private = "private",
}interface FunctionDeclarationStructure extends Structure, JSDocableNodeStructure, StatementedNodeStructure {
kind: StructureKind.Function;
name: string;
parameters?: ParameterDeclarationStructure[];
returnType?: string;
typeParameters?: TypeParameterDeclarationStructure[];
isAsync?: boolean;
isGenerator?: boolean;
isExported?: boolean;
isDefaultExport?: boolean;
overloads?: FunctionDeclarationOverloadStructure[];
}
interface ParameterDeclarationStructure extends Structure, DecoratableNodeStructure {
kind: StructureKind.Parameter;
name: string;
type?: string;
initializer?: string | WriterFunction;
hasQuestionToken?: boolean;
isRestParameter?: boolean;
scope?: Scope;
}interface InterfaceDeclarationStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.Interface;
name: string;
extends?: string[];
typeParameters?: TypeParameterDeclarationStructure[];
isExported?: boolean;
isDefaultExport?: boolean;
properties?: PropertySignatureStructure[];
methods?: MethodSignatureStructure[];
callSignatures?: CallSignatureDeclarationStructure[];
constructSignatures?: ConstructSignatureDeclarationStructure[];
indexSignatures?: IndexSignatureDeclarationStructure[];
}
interface PropertySignatureStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.PropertySignature;
name: string;
type?: string;
hasQuestionToken?: boolean;
isReadonly?: boolean;
}
interface MethodSignatureStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.MethodSignature;
name: string;
parameters?: ParameterDeclarationStructure[];
returnType?: string;
typeParameters?: TypeParameterDeclarationStructure[];
hasQuestionToken?: boolean;
}interface ImportDeclarationStructure extends Structure {
kind: StructureKind.ImportDeclaration;
moduleSpecifier: string;
defaultImport?: string;
namespaceImport?: string;
namedImports?: (string | ImportSpecifierStructure)[];
isTypeOnly?: boolean;
}
interface ImportSpecifierStructure {
name: string;
alias?: string;
isTypeOnly?: boolean;
}
interface ExportDeclarationStructure extends Structure {
kind: StructureKind.ExportDeclaration;
moduleSpecifier?: string;
namedExports?: (string | ExportSpecifierStructure)[];
namespaceExport?: string;
isTypeOnly?: boolean;
}
interface ExportSpecifierStructure {
name: string;
alias?: string;
isTypeOnly?: boolean;
}interface VariableStatementStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.VariableStatement;
declarationKind: VariableDeclarationKind;
declarations: VariableDeclarationStructure[];
isExported?: boolean;
isDefaultExport?: boolean;
}
interface VariableDeclarationStructure {
name: string;
type?: string;
initializer?: string | WriterFunction;
}
interface TypeAliasDeclarationStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.TypeAlias;
name: string;
type: string;
typeParameters?: TypeParameterDeclarationStructure[];
isExported?: boolean;
isDefaultExport?: boolean;
}
interface EnumDeclarationStructure extends Structure, JSDocableNodeStructure {
kind: StructureKind.Enum;
name: string;
members: EnumMemberStructure[];
isConst?: boolean;
isExported?: boolean;
isDefaultExport?: boolean;
}
interface EnumMemberStructure extends Structure, JSDocableNodeStructure {
name: string;
value?: string | number;
}Utility for generating formatted code with proper indentation and structure.
class CodeBlockWriter {
/** Write text */
write(text: string): this;
/** Write a line of text */
writeLine(text?: string): this;
/** Write a new line */
newLine(): this;
/** Write spaces for current indentation level */
indent(): this;
/** Increase indentation level */
indentBlock(): this;
/** Write text within a block with increased indentation */
inlineBlock(block: () => void): this;
/** Write a code block with braces and proper indentation */
block(block?: () => void): this;
/** Conditionally write text */
conditionalWrite(condition: boolean, text: string): this;
/** Get the current indentation level */
getIndentationLevel(): number;
/** Set the indentation level */
setIndentationLevel(indentationLevel: number): this;
/** Get the generated string */
toString(): string;
}
type WriterFunction = (writer: CodeBlockWriter) => void;Static utility class providing common writer functions for code generation.
class Writers {
/** Create a writer function for object properties */
static object(obj: { [key: string]: string | WriterFunction }): WriterFunction;
/** Create a writer function for array elements */
static array(elements: (string | WriterFunction)[]): WriterFunction;
/** Create a writer function for union types */
static unionType(types: string[]): WriterFunction;
/** Create a writer function for intersection types */
static intersectionType(types: string[]): WriterFunction;
/** Create a writer function for conditional expressions */
static conditionalExpression(condition: string, whenTrue: string, whenFalse: string): WriterFunction;
/** Create a writer function for assertions */
static assertion(type: string, expr: string): WriterFunction;
}
type WriterFunctionOrValue = string | WriterFunction;Usage Examples:
import { Project, StructureKind, Scope, VariableDeclarationKind } from "ts-morph";
const project = new Project();
const sourceFile = project.createSourceFile("generated.ts", "");
// Generate a class
const classDeclaration = sourceFile.addClass({
kind: StructureKind.Class,
name: "UserService",
isExported: true,
properties: [
{
kind: StructureKind.Property,
name: "users",
type: "User[]",
scope: Scope.Private,
initializer: "[]",
},
],
constructors: [
{
kind: StructureKind.Constructor,
parameters: [
{
kind: StructureKind.Parameter,
name: "apiClient",
type: "ApiClient",
scope: Scope.Private,
},
],
statements: ["// Constructor implementation"],
},
],
methods: [
{
kind: StructureKind.Method,
name: "getUsers",
returnType: "Promise<User[]>",
isAsync: true,
statements: [
"const response = await this.apiClient.get('/users');",
"return response.data;",
],
},
{
kind: StructureKind.Method,
name: "createUser",
parameters: [
{
kind: StructureKind.Parameter,
name: "userData",
type: "CreateUserData",
},
],
returnType: "Promise<User>",
isAsync: true,
statements: [
"const response = await this.apiClient.post('/users', userData);",
"return response.data;",
],
},
],
});
// Generate an interface
sourceFile.addInterface({
kind: StructureKind.Interface,
name: "User",
isExported: true,
properties: [
{
kind: StructureKind.PropertySignature,
name: "id",
type: "string",
},
{
kind: StructureKind.PropertySignature,
name: "name",
type: "string",
},
{
kind: StructureKind.PropertySignature,
name: "email",
type: "string",
},
{
kind: StructureKind.PropertySignature,
name: "age",
type: "number",
hasQuestionToken: true,
},
],
});
// Generate a type alias
sourceFile.addTypeAlias({
kind: StructureKind.TypeAlias,
name: "CreateUserData",
type: "Omit<User, 'id'>",
isExported: true,
});
// Generate imports
sourceFile.addImportDeclaration({
kind: StructureKind.ImportDeclaration,
moduleSpecifier: "./api-client",
namedImports: ["ApiClient"],
});
// Generate an enum
sourceFile.addEnum({
kind: StructureKind.Enum,
name: "UserRole",
isExported: true,
members: [
{ name: "Admin", value: "'admin'" },
{ name: "User", value: "'user'" },
{ name: "Guest", value: "'guest'" },
],
});
// Generate variables
sourceFile.addVariableStatement({
kind: StructureKind.VariableStatement,
declarationKind: VariableDeclarationKind.Const,
isExported: true,
declarations: [
{
name: "DEFAULT_USER_ROLE",
type: "UserRole",
initializer: "UserRole.User",
},
],
});
console.log(sourceFile.getFullText());Advanced Code Generation with Writers:
import { Project, Writers } from "ts-morph";
const project = new Project();
const sourceFile = project.createSourceFile("complex.ts", "");
// Using writer functions for complex code generation
sourceFile.addFunction({
name: "createValidator",
returnType: "ValidationFunction",
isExported: true,
parameters: [
{
name: "schema",
type: "ValidationSchema",
},
],
statements: [
(writer) => {
writer.writeLine("return (data: any) => {");
writer.indent().writeLine("const errors: string[] = [];");
writer.newLine();
writer.writeLine("// Validation logic here");
writer.newLine();
writer.writeLine("return {");
writer.indent().writeLine("isValid: errors.length === 0,");
writer.writeLine("errors");
writer.outdent().writeLine("};");
writer.outdent().writeLine("};");
},
],
});
// Using Writers utility methods
sourceFile.addTypeAlias({
name: "ComplexType",
type: Writers.unionType([
"string",
"number",
Writers.object({
name: "string",
age: "number",
}).toString(),
]).toString(),
isExported: true,
});Install with Tessl CLI
npx tessl i tessl/npm-ts-morph