A collection of transformers for ts-morph to refactor react code
npm install ts-morph-react


A powerful collection of AST transformers for ts-morph to automate React code refactoring. Enforce consistent code patterns, modernize your codebase, and enforce best practices with declarative, composable transformers.
- š Enforce Direct Exports - Convert separate export statements to direct exports on function declarations
- šÆ Function Components - Automatically convert function declarations to arrow function components with proper typing
- š¦ Named Imports - Transform default imports to named imports for consistency
- šØ Code Formatting - Format code and organize imports according to your style guide (using ESLint, Prettier or Typescript Language Featues)
- ā” Composable - Mix and match transformers to create your refactoring pipeline
- š”ļø Type-Safe - Built with TypeScript for a fully typed experience
- š AST-Powered - Leverage ts-morph for precise, reliable code transformations
``bash`
npm install ts-morph-reactor
pnpm add ts-morph-reactor
yarn add ts-morph-react
`typescript
import { Project } from 'ts-morph'
import { transform } from 'ts-morph-react'
const project = new Project()
const sourceFile = project.addSourceFileAtPath('src/Button.tsx')
// Run transformers with your configuration
await transform(sourceFile, {
enforceDirectExports: true,
enforceFunctionComponent: true,
enforceNamedImports: true,
enforceFormat: true,
enforcePrettier: true,
enforceEslint: true,
enforceLineSeparation: true
})
// Save changes
await sourceFile.save()
`
Converts separate export statement to direct exports.
ā Before:
`tsx
function Button
return
}
export { Button }
`
ā
After:
`tsx`
export function Button(props) {
return
}
Converts plain function components to properly typed React.FunctionComponent components, preserving prop types.
ā Before:
`tsx`
function Button(props: ButtonProps) {
return
}
ā
After:
`tsx`
const Button: React.FunctionComponent
return
}
Transforms default imports to named imports for better tree-shaking and consistency.
ā Before:
`tsx
import * as React from 'react'
export const Button: React.FunctionComponent
return
}
`
ā
After:
`tsx
import { FunctionComponent } from 'react'
export const Button: FunctionComponent
return
}
`
Formats code and organizes imports according to your style guide. Respects all standard TypeScript formatting options, eslint rules and prettier options.
Usage:
`tsx
import { transform } from 'ts-morph-react'
await transform(sourceFile, {
enforceFormat: true,
enforcePrettier: true,
enforceEslint: true,
enforceLineSeparation: true,
format: {
indentSize: 2,
convertTabsToSpaces: true,
semicolons: ts.SemicolonPreference.Remove
},
eslint: {
'@stylistic/quotes': ['error', 'single']
},
prettier: {
semi: false,
singleQuote: true
}
})
`
ā Before:
`tsx
import * as React from 'react';
import { Text } from '@/components/Text';
export const Button: React.FunctionComponent
label
}) => {
return ;
};
`
ā
After:
`tsx
import * as React from 'react'
import { Text } from '@/components/Text'
export const Button: React.FunctionComponent
return
}
`
Applies transformers to a source file.
`typescript`
interface TransformerConfig {
enforceDirectExports: boolean
enforceFunctionComponent: boolean
enforceNamedImports: boolean
enforceFormat: boolean
enforceLineSeparation: boolean
enforceEslint: boolean
enforcePrettier: boolean
format: {
baseIndentSize: number
convertTabsToSpaces: boolean
ensureNewLineAtEndOfFile: boolean
indentMultiLineObjectLiteralBeginningOnBlankLine: boolean
indentSize: number
indentStyle: IndentStyle
indentSwitchCase: boolean
insertSpaceAfterCommaDelimiter: boolean
insertSpaceAfterConstructor: boolean
insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean
insertSpaceAfterKeywordsInControlFlowStatements: boolean
insertSpaceAfterOpeningAndBeforeClosingEmptyBraces: boolean
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: boolean
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean
insertSpaceAfterSemicolonInForStatements: boolean
insertSpaceAfterTypeAssertion: boolean
insertSpaceBeforeAndAfterBinaryOperators: boolean
insertSpaceBeforeFunctionParenthesis: boolean
insertSpaceBeforeTypeAnnotation: boolean
newLineCharacter: string
placeOpenBraceOnNewLineForControlBlocks: boolean
placeOpenBraceOnNewLineForFunctions: boolean
semicolons: SemicolonPreference
tabSize: number
trimTrailingWhitespace: boolean
},
eslint: {
'@stylistic/*': ['error'],
'@typescript-eslint/*': ['error']
},
prettier: {
semi: false,
singleQuote: true,
jsxSingleQuote: true,
arrowParens: 'always',
bracketSameLine: true,
objectWrap: 'collapse',
printWidth: 120
}
}
`bashBuild the library
pnpm build
$3
The project uses vitest with snapshot testing to ensure transformer behavior is consistent and intentional:
`bash
Run tests once
pnpm testRun in watch mode
pnpm test:watchUpdate snapshots after intentional changes
pnpm test -- -uRun specific test file
pnpm test enforceFormat
``ā
Good for:
- Enforcing code patterns across your codebase
- Large-scale refactoring of React components
- Automating style guide compliance
- One-time migrations (class ā function components, etc.)
- Building custom code generators and linters
ā Not ideal for:
- Real-time code formatting (use Prettier for that)
- Rename refactoring with complex scope analysis (use your IDE)
- Performance-critical transformations of very large codebases
ts-morph-react is built on top of ts-morph, a fantastic library that provides a fluent API for manipulating TypeScript ASTs. If you need lower-level control, you can access the ts-morph APIs directly.
Contributions are welcome! Please feel free to submit a Pull Request.
MIT Ā© Tobias Strebitzer
- ts-morph - The underlying AST manipulation library
- TypeScript Compiler API - For deeper TypeScript understanding