Renaming TypeScript interfaces with ts-morph

ts-morph is a tool to write codemods for TypeScript — programs that modify TypeScript code.

Here’s how I removed the I prefixes of all interfaces in a project: IDog becomes Dog.

  1. Create a file with the codemod, src/remove-prefixes.ts:
import { Project } from 'ts-morph';
 
// Initialize a project with our tsconfig file
const project = new Project({
  tsConfigFilePath: 'tsconfig.json'
});
 
// Get all project files
const sourceFiles = project.getSourceFiles();
 
sourceFiles.forEach(sourceFile => {
  console.log('👉', sourceFile.getBaseName());
 
  // Get all interfaces in a file
  const interfaces = sourceFile.getInterfaces();
 
  interfaces.forEach(i => {
    // IDog → Dog
    const name = i.getName();
    const nextName = name.replace(/^I([A-Z])/, '$1');
    if (name === nextName) {
      return;
    }
 
    // Rename interface
    console.log(name, '->', nextName);
    i.rename(nextName, {
      renameInComments: true,
      renameInStrings: true
    });
  });
 
  console.log();
});
 
// Save all changed files
project.saveSync();
  1. Install dependencies:
npm install --save-dev ts-morph
  1. Run the codemod:
ts-node --compiler-options '{"module": "commonjs"}' src/remove-prefixes.ts

Note We need to override compiler options here because our project is using webpack and ECMAScript modules aren’t transpiled, which is required for Node.js.

Caveats

This codemod doesn’t do anything with naming conflict. For example, if we already have a Dog component or class and we’re importing the IDog interface into the same file, we’ll have a naming conflict: both, the component and the interface will be called Dog.