A modern, TypeScript-based CLI tool that automatically refactors your React codebase to use the standalone prop-types package instead of the deprecated React.PropTypes. Supports JavaScript, JSX, TypeScript, and TSX files with robust transformation capabilities.
When React v15.5 was released in 2017, PropTypes was deprecated from the core React package and moved to a separate prop-types package. Many legacy React projects still use the old React.PropTypes syntax, which is no longer supported in modern React versions.
This CLI tool automates the migration process by:
- β
Detecting legacy PropTypes usage - Scans for
React.PropTypespatterns - β
Removing PropTypes from React imports - Cleans up
import { PropTypes }from React - β
Adding standalone prop-types import - Adds
import PropTypes from 'prop-types' - β
Replacing usage patterns - Changes
React.PropTypes.stringtoPropTypes.string - β
Handling complex nested patterns - Supports complex PropTypes like
PropTypes.arrayOf(PropTypes.shape(...)) - β Processing entire codebases - Recursively processes directories and subdirectories
- β
Installing dependencies - Optionally installs the
prop-typespackage automatically - β TypeScript & JSX Support - Works with .js, .jsx, .ts, and .tsx files
- β Advanced Pattern Recognition - Handles complex import patterns and edge cases
npm install -g move-prop-types
# or with pnpm
pnpm add -g move-prop-types
# or with yarn
yarn global add move-prop-typesnpm install --save-dev move-prop-types
# or with pnpm
pnpm add --save-dev move-prop-types
# or with yarn
yarn add --dev move-prop-typesUsage: move-prop-types|mpt [options] [file|folder]
Options:
-V, --version output the version number
-I, --install install prop-types package and continue with transformation
-P, --path <path> transform a specific file
-F, --folder <folder> transform all .js/.jsx/.ts/.tsx files in a folder (recursive)
-h, --help display help for command# Transform JavaScript/JSX files
mpt -P src/components/UserProfile.jsx
mpt -P src/utils/validators.js
# Transform TypeScript/TSX files
mpt -P src/components/UserProfile.tsx
mpt -P src/types/PropTypes.ts
# Transform with automatic prop-types installation
mpt -I -P src/components/UserProfile.tsx
# Transform a file with relative path
mpt -P ./components/Header.ts
# Transform multiple files (run command for each)
mpt -P src/components/Button.jsx
mpt -P src/components/Modal.tsx
mpt -P src/utils/validators.ts# Transform all .js/.jsx/.ts/.tsx files in src directory recursively
mpt -F src
# Transform entire project with prop-types installation
mpt -I -F .
# Transform specific subdirectories
mpt -F src/components
mpt -F src/pages
mpt -F src/utils
# Large TypeScript project with automatic dependency installation
mpt -I -F src# 1. Install move-prop-types globally
npm install -g move-prop-types
# 2. Navigate to your React project
cd my-react-project
# 3. Install prop-types and transform entire codebase
mpt -I -F src
# 4. Verify changes and test your application
npm test# Transform only component files
mpt -F src/components
# Transform only utility files that use PropTypes
mpt -P src/utils/propTypeValidators.js
mpt -P src/hoc/withPropTypes.jsBefore transformation:
import React, { Component, PropTypes } from 'react';
class UserProfile extends Component {
render() {
const { name, email, age, isActive } = this.props;
return (
<div className="user-profile">
<h2>{name}</h2>
<p>Email: {email}</p>
<p>Age: {age}</p>
{isActive && <span className="active">Active User</span>}
</div>
);
}
}
UserProfile.propTypes = {
name: React.PropTypes.string.isRequired,
email: React.PropTypes.string.isRequired,
age: React.PropTypes.number,
isActive: React.PropTypes.bool
};
UserProfile.defaultProps = {
age: 0,
isActive: false
};
export default UserProfile;After transformation:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class UserProfile extends Component {
render() {
const { name, email, age, isActive } = this.props;
return (
<div className="user-profile">
<h2>{name}</h2>
<p>Email: {email}</p>
<p>Age: {age}</p>
{isActive && <span className="active">Active User</span>}
</div>
);
}
}
UserProfile.propTypes = {
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
age: PropTypes.number,
isActive: PropTypes.bool
};
UserProfile.defaultProps = {
age: 0,
isActive: false
};
export default UserProfile;Before transformation:
import React, { PropTypes } from 'react';
const DataTable = ({ data, columns, onRowClick, pagination, loading }) => {
// Component implementation
return <div>DataTable Component</div>;
};
DataTable.propTypes = {
data: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
columns: React.PropTypes.arrayOf(React.PropTypes.shape({
key: React.PropTypes.string.isRequired,
title: React.PropTypes.string.isRequired,
render: React.PropTypes.func,
sortable: React.PropTypes.bool
})).isRequired,
onRowClick: React.PropTypes.func,
pagination: React.PropTypes.oneOfType([
React.PropTypes.bool,
React.PropTypes.shape({
page: React.PropTypes.number,
pageSize: React.PropTypes.number,
total: React.PropTypes.number
})
]),
loading: React.PropTypes.bool
};
export default DataTable;After transformation:
import React from 'react';
import PropTypes from 'prop-types';
const DataTable = ({ data, columns, onRowClick, pagination, loading }) => {
// Component implementation
return <div>DataTable Component</div>;
};
DataTable.propTypes = {
data: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
render: PropTypes.func,
sortable: PropTypes.bool
})).isRequired,
onRowClick: PropTypes.func,
pagination: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.shape({
page: PropTypes.number,
pageSize: PropTypes.number,
total: PropTypes.number
})
]),
loading: PropTypes.bool
};
export default DataTable;Before transformation:
import React, { PropTypes } from 'react';
function Button({ label, onClick, disabled, variant, size }) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant} btn-${size}`}
>
{label}
</button>
);
}
Button.propTypes = {
label: React.PropTypes.string.isRequired,
onClick: React.PropTypes.func.isRequired,
disabled: React.PropTypes.bool,
variant: React.PropTypes.oneOf(['primary', 'secondary', 'danger']),
size: React.PropTypes.oneOf(['small', 'medium', 'large'])
};
Button.defaultProps = {
disabled: false,
variant: 'primary',
size: 'medium'
};
export default Button;After transformation:
import React from 'react';
import PropTypes from 'prop-types';
function Button({ label, onClick, disabled, variant, size }) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant} btn-${size}`}
>
{label}
</button>
);
}
Button.propTypes = {
label: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
disabled: PropTypes.bool,
variant: PropTypes.oneOf(['primary', 'secondary', 'danger']),
size: PropTypes.oneOf(['small', 'medium', 'large'])
};
Button.defaultProps = {
disabled: false,
variant: 'primary',
size: 'medium'
};
export default Button;Before transformation:
import React, { FC, PropTypes } from 'react';
interface MyComponentProps {
title: string;
count?: number;
onClick: (id: number) => void;
}
const MyComponent: FC<MyComponentProps> = ({ title, count = 0, onClick }) => {
return (
<div>
<h2>{title}</h2>
<p>Count: {count}</p>
<button onClick={() => onClick(count)}>Click me</button>
</div>
);
};
MyComponent.propTypes = {
title: React.PropTypes.string.isRequired,
count: React.PropTypes.number,
onClick: React.PropTypes.func.isRequired
};
export default MyComponent;After transformation:
import React, { FC } from 'react';
import PropTypes from 'prop-types';
interface MyComponentProps {
title: string;
count?: number;
onClick: (id: number) => void;
}
const MyComponent: FC<MyComponentProps> = ({ title, count = 0, onClick }) => {
return (
<div>
<h2>{title}</h2>
<p>Count: {count}</p>
<button onClick={() => onClick(count)}>Click me</button>
</div>
);
};
MyComponent.propTypes = {
title: PropTypes.string.isRequired,
count: PropTypes.number,
onClick: PropTypes.func.isRequired
};
export default MyComponent;- TypeScript Support: Built with TypeScript for better reliability and type safety
- Modern Tooling: Uses latest ESLint, Prettier, and build tools
- Comprehensive Testing: Full test suite with unit and integration tests
- Recursive Processing: Handles entire directory structures
- Smart Detection: Only processes files that actually use PropTypes
- Safe Transformations: Preserves existing prop-types imports
- Multiple Import Patterns: Handles various React import styles
- TypeScript Compatibility: Preserves TypeScript syntax, interfaces, and type annotations
- Advanced Pattern Detection: Handles complex PropTypes patterns including middle-position imports
- Node.js 18+
- pnpm (recommended) or npm
# Clone the repository
git clone https://github.com/vish288/move-prop-types.git
cd move-prop-types
# Install dependencies
pnpm install
# Build the project
pnpm run build
# Run tests
pnpm test
# Run linting
pnpm run lintsrc/
βββ core.ts # CLI command setup and argument parsing
βββ helper.ts # Core transformation logic with TypeScript support
βββ ast-helper.ts # Advanced AST-based transformation (experimental)
βββ ast-transformer.ts # AST parsing and transformation utilities
βββ constants.ts # Regular expressions and transformation patterns
βββ types.ts # TypeScript type definitions
βββ updateFile.ts # Build utility for adding shebang
test/
βββ unit/ # Unit tests for individual modules
β βββ helper.test.ts
β βββ ast-transformer.test.ts
β βββ constants.test.ts
β βββ core.test.ts
βββ integration/ # Integration tests for real-world scenarios
βββ fixtures/ # Test files for various transformation scenarios
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- β v1.0.0 - Stable release with full TypeScript support
- β v0.20.1-beta.1 - Beta release with TypeScript support
- π NPM Publishing - Automatic publishing configured
The following GitHub releases are ready but not yet published to npm:
v0.20.1-beta.1(TypeScript support beta)v1.0.0(stable release with TypeScript support)
These will be automatically published once the repository maintainer configures the NPM_TOKEN secret.
This repository includes an automated system to:
- β Detect missing versions between GitHub releases and npm
- β Publish automatically when NPM_TOKEN is configured
- β Daily checks for any missing versions
- β Manual triggers available via GitHub Actions
For maintainers: See docs/NPM_PUBLISHING.md for setup instructions.
- Node.js: Version 18 or higher
- File Types: Supports
.js,.jsx,.ts, and.tsxfiles - React Versions: Compatible with all React versions that used
React.PropTypes
If you encounter any issues or have feature requests, please open an issue on GitHub.
This project is licensed under the MIT License - see the LICENSE file for details.
- React team for the smooth transition process
- The community for feedback and contributions
- All users who have helped improve this tool