ts-morph Documentation

TypeScript Compiler API wrapper for static analysis and programmatic code changes.

6,149 stars TypeScript TypeScript 1 file ยท ~5,759 tokens #ast#code-generation#javascript#static-analysis#typescript
RAW Doc

1. Project Overview & Quickstart (dsherret/ts-morph)

File: README.md

Monorepo for ts-morph and related projects.

Packages

  • ts-morph - TypeScript Compiler API wrapper. Provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code.
  • @ts-morph/bootstrap - Separate library for getting quickly setup with the Compiler API.

Resources


File: Readme.md

Monorepo for ts-morph and related projects.

Packages

  • ts-morph - TypeScript Compiler API wrapper. Provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code.
  • @ts-morph/bootstrap - Separate library for getting quickly setup with the Compiler API.

Resources


File: readme.md

Monorepo for ts-morph and related projects.

Packages

  • ts-morph - TypeScript Compiler API wrapper. Provides an easier way to programmatically navigate and manipulate TypeScript and JavaScript code.
  • @ts-morph/bootstrap - Separate library for getting quickly setup with the Compiler API.

Resources


File: docs/details/ambient.md


title: Ambient

Ambient

Certain nodes in TypeScript can be ambient. For example, all nodes within a declaration file are ambient.

Testing if ambient

Use isAmbient():

ts
classDeclaration.isAmbient(); // returns: boolean

This will do several checks to see if it's an ambient declaration.

`declare` keyword

Check for the declare keyword:

ts
classDeclaration.hasDeclareKeyword(); // returns: boolean

Or get the declare keyword if it exists:

ts
classDeclaration.getDeclareKeyword();

Or set if it has a declare keyword:

ts
classDeclaration.setHasDeclareKeyword(true);
classDeclaration.setHasDeclareKeyword(false);

File: docs/details/async.md


title: Async

Async

Certain nodes in TypeScript can have an async keyword modifier.

Is async

A node can be tested if it's async using the isAsync() method:

ts
functionDeclaration.isAsync(); // returns: boolean

`async` keyword

Get the async keyword if it exists:

ts
functionDeclaration.getAsyncKeyword();

Set async

Set if the declaration is async using setIsAsync:

ts
functionDeclaration.setIsAsync(true);

File: docs/details/classes.md


title: Classes

Class Declarations

Class declarations can be retrieved from source files, namespaces, or function bodies:

ts
const classes = sourceFile.getClasses();
const class1 = sourceFile.getClass("Class1");
const firstClassWithConstructor = sourceFile.getClass(c => c.getConstructors().length > 0);

Name

It's important to note that class declarations may not have a name. For example:

ts
export default class {
  // etc...
}

For this reason, the methods like .getName() and .getNameNode() are nullable on ClassDeclaration.

Add/Insert

Add or insert classes to a source file, namespace, or function like declarations by calling addClass(), addClasses(), insertClass(), or insertClasses().

ts
const classDeclaration = sourceFile.addClass({
  name: "ClassName",
});

Remove

Call .remove():

ts
classDeclaration.remove();

Extends expression

Will return ExpressionWithTypeArguments | undefined:

ts
const extendsExpression = classDeclaration.getExtends();

Set the extends expression:

ts
classDeclaration.setExtends("BaseClass");

Remove it:

ts
classDeclaration.removeExtends();

Implements expressions

Will return ExpressionWithTypeArguments[]:

ts
const implementsExpressions = classDeclaration.getImplements();

Add or insert implements expressions:

ts
classDeclaration.addImplements("Named");
classDeclaration.addImplements(["Named", "Aged"]);
classDeclaration.insertImplements(1, "Named");
classDeclaration.insertImplements(1, ["Named", "Aged"]);

Remove an expression:

ts
classDeclaration.removeImplements(0); // index
classDeclaration.removeImplements(classDeclaration.getImplements()[0]); // node

Base Types

Get the base types:

ts
const baseTypes = classDeclaration.getBaseTypes(); // returns: Type[]

This is useful to use if you don't know if the class could possibly extend a mixin or a class.

Base Class

Get the base class:

ts
const baseClass = classDeclaration.getBaseClass(); // returns: ClassDeclaration | undefined

Note: This is not a useful method to use if the base could possibly be a mixin. If you expect mixins, then use .getBaseTypes().

Derived Classes

Will return all the class declarations that derive from the current class:

ts
const derivedClasses = classDeclaration.getDerivedClasses();

Constructor

Constructors can be retreived via getConstructors. This returns all the constructors in an ambient context, but will only return the
implementation constructor otherwise.

ts
const constructors = classDeclaration.getConstructors();

Add or insert a constructor or constructors by calling addConstructor(), addConstructors(), insertConstructor(), or insertConstructors().

ts
const ctor = classDeclaration.addConstructor({
  /* options like parameters may go here */
});

Methods

Get instance methods:

ts
const instanceMethods = classDeclaration.getInstanceMethods();
const myMethod = classDeclaration.getInstanceMethod("myMethod");
const firstMethodWith2Params = classDeclaration.getInstanceMethod(m => m.getParameters().length === 2);

Get the static methods:

ts
const staticMethods = classDeclaration.getStaticMethods();
const myStaticMethod = classDeclaration.getStaticMethod("myMethod");
const firstStaticMethodWith2Params = classDeclaration.getStaticMethod(m => m.getParameters().length === 2);

Add/Insert

Add or insert methods by using insertMethods(), insertMethod, addMethod, or addMethods:

ts
const method = classDeclaration.addMethod({ isStatic: true, name: "myMethod", returnType: "string" });

Remove

Call .remove():

ts
method.remove();

Properties

Get the instance properties (includes parameter properties):

ts
const instanceProperties = classDeclaration.getInstanceProperties();
const myProperty = classDeclaration.getInstanceProperty("myProperty");
const myStringProperty = classDeclaration.getInstanceProperty(p =>
    Node.isPropertyDeclaration(p) && p.getType().getText() === "string");

Get the static properties:

ts
const staticProperties = classDeclaration.getStaticProperties();
const myStaticProperty = classDeclaration.getStaticProperty("myStaticProperty");
const myStaticStringProperty = classDeclaration.getStaticProperty(p =>
    Node.isPropertyDeclaration(p) && p.getType().getText() === "string");

Add/Insert

Add or insert properties by using insertProperties(), insertProperty, addProperty, or addProperties:

ts
const property = classDeclaration.addProperty({
  isStatic: true,
  name: "prop",
  type: "string",
});

Add or insert get accessors by using insertGetAccessors(), insertGetAccessor, addGetAccessor, or addGetAccessors:

ts
const getAccessor = classDeclaration.addGetAccessor({
  name: "someNumber",
  returnType: "number",
  statements: ["return 5;"],
});

Add or insert set accessors by using insertSetAccessors(), insertSetAccessor, addSetAccessor, or addSetAccessors:

ts
const setAccessor = classDeclaration.addSetAccessor({
  name: "someNumber",
  parameters: [{ name: "value", type: "number" }],
  statements: ["_someNumber = value;"],
});

Remove

Call .remove():

ts
propertyDeclaration.remove();

Get members

Get all the members regardless of whether static or instance:

ts
const allMembers = classDeclaration.getMembers();

Get instance members including parameter properties:

ts
const instanceMembers = classDeclaration.getInstanceMembers();

Get static members:

ts
const staticMembers = classDeclaration.getStaticMembers();

Extracting an Interface

An interface declaration structure can be extracted from a class by calling classDeclaration.extractInterface(). For example:

ts
// the passed in name is optional and defaults to the class name
const interfaceStructure = classDeclaration.extractInterface(`I${classDeclaration.getName()}`);

Alternatively the static interface declaration structure of a class can be extracted by calling:

ts
const interfaceStructure = classDeclaration.extractStaticInterface(`${classDeclaration.getName()}Static`);

Abstract

Nodes on a class may be abstract.

Get if it's abstract:

ts
method.isAbstract(); // returns: boolean

Get the abstract keyword:

ts
method.getAbstractKeyword(); // returns: node | undefined

Set if abstract:

ts
method.setIsAbstract(true); // set as abstract
method.setIsAbstract(false); // set as not abstract

Constructors

Constructors implement common functions found on function like declarations, but also include a scope.

Methods

Explore the functionality available via auto-complete.

Properties

Explore the functionality available via auto-complete.

Get Accessors

If it exists, get the corresponding set accessor:

ts
const setAccessor = getAccessor.getSetAccessor();

Set Accessors

If it exists, get the corresponding get accessor:

ts
const getAccessor = setAccessor.getGetAccessor();

File: docs/details/comments.md


title: Comments

Comments

ts-morph parses out certain kinds of comments to make them easier to work with. This breaks away from the behaviour in the compiler API because although comments are not very important for compiling, they can be important for programmatic refactoring tasks.

  • Comment Ranges - Comments the compiler api parses out.
  • Comment Nodes - Comments ts-morph parses out in certain scenarios. They extend from ts.Node.

Comment Ranges

Comment ranges are not part of the AST and are generated on request.

  • Leading: Comments that preceed the node after the previous significant tokenโ€”between node.getPos() and node.getStart().
  • Trailing: Comments following the node before the next siginificant token or newline.

WARNING: Since comments are generated on demand and not part of the AST, using one after a
subsequent manipulation to the source file will throw an error.

Retrieving

Leading and trailing comment ranges can be retrieved from any node by calling:

ts
const leadingComments = node.getLeadingCommentRanges();
const trailingComments = node.getTrailingCommentRanges();

Information

Once you have a comment range, there are several self explanatory methods:

  • .getKind() - Returns SyntaxKind.SingleLineCommentTrivia or SyntaxKind.MultiLineCommentTrivia.
  • .getPos() - Position.
  • .getEnd() - End position.
  • .getWidth() - Width (end - pos)
  • .getText() - Text.
  • .wasForgotten() - Returns true if the node was forgotten because a manipulation occured to the source file or its associated node was forgotten.

More Details

Read more about comments in the compiler API documentation here: https://github.com/Microsoft/TypeScript/wiki/Architectural-Overview#trivia

Comment Nodes

These are nodes ts-morph parses out. They do not include all comments, but only the first comment on a line if there are no significant tokens on that line and only in certain contexts (ex. source file statements, class declaration body, function body, namespace body, etc..).

For example, in the following scenario:

ts setup: let functioncall: any;
// do something
functionCall(); // ok

...only the first comment will be parsed out. The second comment is considered a trailing comment range of the function call.

Retrieving

Comment ranges can be retrieved using various #getXWithComments() methods.

For example:

ts setup: let classdec: any, interfacedec: any;
sourceFile.getStatementsWithComments();
classDec.getMembersWithComments();
interfaceDec.getMembersWithComments();
objectLiteralExpression.getPropertiesWithComments();

They also may appear in the results of #getChildren() in certain scenarios. For example:

ts
const children = sourceFile.getChildSyntaxListOrThrow().getChildren();

This extends the behaviour of the compiler API.

Why?

The reason this is done is to make inserting before or after comments possible. For example, given the following source file:

ts setup: let functioncall: any;
// 1
// 2
functionCall();

It is possible to insert a statement after the first comment by specifying sourceFile.insertStatement(1, "// new comment");, which would modify the source file to be:

ts setup: let functioncall: any;
// 1
// new comment
// 2
functionCall();

Removing Comments

To remove a comment node, call #remove() on it:

ts
sourceFile.getStatementsWithComments()[0].remove();

This will remove the comment and any of its trailing comment nodes.

Trailing comment ranges of comment nodes

Comment nodes may have trailing comment ranges. For example, given the following source file:

ts
/* 1 */ // 2

...the text /* 1 */ is considered the comment node, while // 2 is the trailing comment range. // 2 can be retrieved with the following code:

ts
const secondComment = sourceFile.getStatementsWithComments()[0].getTrailingCommentRanges()[0];

File: docs/details/decorators.md


title: Decorators

Decorators

Decorators can be retrieved from class related nodes by calling the getDecorators() method.

ts
const decorators = classDeclaration.getDecorators();

Name

Get the name or fully qualified name of a decorator by using the getName() or getFullName() functions respectively.

For example, given the following code:

ts setup: const obj: { decorator: any; };
@obj.decorator
class Identifier {
}

The following happens:

ts
decorator.getName(); // "decorator"
decorator.getFullName(); // "obj.decorator"

Decorator factory

Decorators with parenthesis (ex. @decorator(3)) are decorator factories, while decorators without (ex. @decorator) are not.

ts
decorator.isDecoratorFactory(); // returns: boolean

Set as a decorator factory or not:

ts
decorator.setIsDecoratorFactory(true);

Arguments

Get the decorator's arguments by calling .getArguments():

ts
const args = decorator.getArguments(); // returns: Expression[]

Add and insert via .addArgument(...), .insertArguments(...), .addArgument(...), or .addArguments(...).

ts
const args = decorator.insertArguments(1, ["5", "6"]);

And remove them by calling .removeArgument():

ts setup: const args: any;
// specify the index
decorator.removeArgument(0);
// or specify the argument node
decorator.removeArgument(args[0]);

Type arguments

Get the decorator's type arguments by calling .getTypeArguments():

ts
const typeArgs = decorator.getTypeArguments(); // returns: TypeNode[]

Add and insert via .insertTypeArgument(...), .insertTypeArguments(...), .addTypeArgument(...), or .addTypeArguments(...).

ts
const typeArgs = decorator.insertTypeArguments(1, ["string", "number"]);

And remove them by calling .removeTypeArgument():

ts setup: let typeargs: typenode[];
// specify the index
decorator.removeTypeArgument(0);
// or specify the type argument node
decorator.removeTypeArgument(typeArgs[0]);

Call expression

Decorator factories are call expressions. Get the call expression by calling:

ts
const callExpression = decorator.getCallExpression(); // returns: CallExpression | undefined

Add/Insert decorators

Decorators can be added or inserted by calling addDecorator(decorator), addDecorators(decorators), insertDecorator(index, decorator), or insertDecorators(index, decorators).

For example:

ts
classDeclaration.addDecorator({
  name: "MyDecorator",
  arguments: ["3", `"some string"`],
});

Remove decorators

Call .remove():

ts
decorator.remove();

File: docs/details/documentation.md


title: JS Docs

JS Docs

Certain nodes can have JS docs. For example:

ts setup: interface person {}
/**
 * Gets the name.
 * @param person - Person to get the name from.
 */
function getName(person: Person) {
  // ...
}

Get all JS doc nodes

Get all the JS doc nodes by using getJsDocs():

ts
functionDeclaration.getJsDocs(); // returns: JSDoc[]

Add/insert docs

Add or insert JS doc comments using the addJsDoc(), addJsDocs(), insertJsDoc(), and insertJsDocs() methods.

For example:

ts
// adds /** Some description... */
const docNode = classDeclaration.addJsDoc({
});
// or to force it to be multi-line, add a newline to the front of the string
classDeclaration.addJsDoc({
});
// or with tags
classDeclaration.addJsDoc({
  tags: [{
    tagName: "param",
    text: "value - My value.",
  }],
});

JSDoc Nodes

Get the description:

ts
// Getting the node from the example at the top of this file.
const jsDoc = functionDeclaration.getJsDocs()[0];
jsDoc.getDescription(); // returns string: "Gets the name."

Get the tags:

ts
const tags = jsDoc.getTags();
tags[0].getText(); // "@param person - Person to get the name from."

Get the inner text (the text without the surrounding comment):

ts
jsDoc.getInnerText(); // "Gets the name.\n@param person - Person to get the name from."

File: docs/details/enums.md


title: Enums

Enums

Enums can be retrieved from source files, namespaces, or function bodies:

ts
const enums = sourceFile.getEnums();
const enum1 = sourceFile.getEnum("Enum1");
const enum2 = sourceFile.getEnum(e => e.getMembers().length === 5);

Add/Insert

Add or insert enums to a source file, namespace, or function like declarations by calling addEnum(), addEnums(), insertEnum(), or insertEnums().

ts
const enumDeclaration = sourceFile.addEnum({
  name: "EnumName",
  members: [{
    name: "member",
  }],
});

Remove

Call .remove():

ts
enumDeclaration.remove();

Get all members

Use getMembers():

ts
const members = enumDeclaration.getMembers();

Get member

Use getMember():

ts
const member1 = enumDeclaration.getMember("member1");
const member2 = enumDeclaration.getMember(m => m.getValue() === 1);

Add/Insert member

Members can be added by calling addMember(), addMembers(), insertMember(), or insertMembers():

ts
const member = enumDeclaration.addMember({
  name: "newMember",
  value: 10,
});

Const enum

Check if it's a const enum via isConstEnum():

ts
enumDeclaration.isConstEnum(); // returns: boolean

Get the const keyword via getConstKeyword():

ts
enumDeclaration.getConstKeyword(); // returns: Node | undefined

Set if it's a const enum via setIsConstEnum(value):

ts
enumDeclaration.setIsConstEnum(true);
enumDeclaration.setIsConstEnum(false);

Enum Members

ts
const member = enumDeclaration.getMember("member");

Value

The value can be retrieved whether it is implicitly or explicitly defined:

ts
enumMember.getValue(); // returns: string | number

It can also be set to a number:

ts
enumMember.setValue(5);

Or a string:

ts
enumMember.setValue("string value");

Removing

Call remove() on it:

ts
enumMember.remove();

2. Official Technical Reference & Guides (dsherret/docs)

GitHub Docs

This repository contains the documentation website code and Markdown source files for docs.github.com.

GitHub's Docs team works on pre-production content in a private repo that regularly syncs with this public repo.

Use the table of contents icon on the top right corner of this document to navigate to a specific section quickly.

Contributing

We accept different types of contributions, including some that don't require you to write a single line of code. For detailed instructions on how to get started with our project, see About contributing to GitHub Docs.

Ways to contribute

On the GitHub Docs site, you can contribute by clicking the Make a contribution button at the bottom of the page to open a pull request for quick fixes like typos, updates, or link fixes.

You can also contribute by creating a local environment or opening a Codespace. For more information, see Setting up your environment to work on GitHub Docs.

For more complex contributions, please open an issue using the most appropriate issue template to describe the changes you'd like to see.

If you're looking for a way to contribute, you can scan through our help wanted board to find open issues already approved for work.

And that's it!

If you're having trouble with your GitHub account, contact Support.

That's how you can easily become a member of the GitHub Docs community. :sparkles:

READMEs

In addition to the README you're reading right now, this repo includes other READMEs that describe the purpose of each subdirectory in more detail:

License

The GitHub product documentation in the assets, content, and data folders are licensed under a CC-BY license.

All other code in this repository is licensed under the MIT license.

When using the GitHub logos, be sure to follow the GitHub logo guidelines.

Thanks :purple_heart:

Thanks for all your contributions and efforts towards improving the GitHub documentation. We thank you for being part of our :sparkles: community :sparkles:!