What it is
ts-morph wraps the TypeScript compiler API in a navigable, mutable object model, making programmatic code analysis and refactoring practical.
Load a project from tsconfig, traverse or query the AST, mutate nodes, and save. Useful for codemods, generation and architectural checks.
Installation
npm install --save-dev ts-morphGetting started
The smallest useful thing you can do with it, and what each part means.
typescript
import { Project, SyntaxKind } from 'ts-morph';
const project = new Project({ tsConfigFilePath: './tsconfig.json' });
for (const file of project.getSourceFiles('src/**/*.ts')) {
for (const cls of file.getClasses()) {
const publicMethods = cls.getMethods().filter((m) => !m.hasModifier(SyntaxKind.PrivateKeyword));
if (publicMethods.length > 20) {
console.warn(`${cls.getName()} has ${publicMethods.length} public methods`);
}
}
}Advanced usage
Where the library earns its place over a simpler alternative.
typescript
const project = new Project({ tsConfigFilePath: './tsconfig.json' });
for (const file of project.getSourceFiles()) {
for (const decl of file.getImportDeclarations()) {
if (decl.getModuleSpecifierValue() === 'lodash') {
// lodash -> per-function imports, for tree shaking
const names = decl.getNamedImports().map((n) => n.getName());
decl.remove();
for (const name of names) {
file.addImportDeclaration({
defaultImport: name,
moduleSpecifier: `lodash/${name}`,
});
}
}
}
}
await project.save(); // writes every modified fileErrors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Changes are not written to disk
- project.save() was not awaited. Mutations live in memory until then.
- Analysis is very slow
- The whole program is being loaded. Restrict the file glob, or set skipAddingFilesFromTsConfig and add only what you need.
Best practices
- Run codemods against a clean git tree so the change can be reviewed and reverted.
- Use getSourceFiles with a glob rather than loading the whole project when you only need part of it.
- Call save() once at the end; per-file saves are much slower.
- Prefer a lint rule when one exists — ts-morph is for what linters cannot express.
Background
Why it exists, and what it was reacting to.
The raw compiler API is powerful and famously awkward. ts-morph, by David Sherret, gives it an ergonomic interface — the basis of many codemods and code generators.
