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.