TypeScript to PropTypes Conversion API
typescript-to-proptypes is a foundational library designed to programmatically convert TypeScript type declarations into React PropTypes definitions. While its version 2.2.1 was last published over four years ago, it serves as an API (Application Programming Interface) that other tools can leverage for integration. It does not provide a direct command-line interface or a complete end-to-end solution for adding PropTypes to components but rather the core logic for translating TypeScript types to their PropTypes equivalents. This package is distinct from `babel-plugin-typescript-to-proptypes`, which is a Babel plugin that consumes a modified version of this API to automate PropTypes generation within a build process. Due to its age and lack of recent updates, developers should be aware that it may not support the latest TypeScript features or React patterns, and is generally considered superseded by TypeScript's native type-checking capabilities for most modern React development. It operates by leveraging the TypeScript Compiler API to parse types and Babel utilities to construct the PropTypes AST.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'kind')
cause This error often occurs when the internal TypeScript AST processing expects a certain node structure that is not found, possibly due to unsupported TypeScript syntax or an incorrect AST traversal path.fixEnsure the TypeScript code being processed is valid and relatively simple. Complex or newer TypeScript features might not be handled. Debug the internal AST traversal logic if extending the library. -
SyntaxError: Unexpected token (X:Y) - while generating code
cause If you're using `@babel/generator` directly with an incorrectly formed Babel AST provided by the conversion process, it can lead to syntax errors during code generation.fixVerify the structure of the Babel AST being passed to `@babel/generator`. The conversion logic from TypeScript to Babel AST for PropTypes might be producing an invalid structure.
Warnings
- deprecated The `typescript-to-proptypes` package has not seen significant updates since August 2021, and its last major release (v2.2.1) was over four years ago. This indicates it is largely unmaintained and may not support newer TypeScript features or syntax.
- gotcha This package is an API, not a direct end-user tool. It provides underlying conversion logic but does not offer a simple command-line interface or a single high-level function for converting a full TypeScript file to PropTypes without additional tooling integration (e.g., Babel plugins).
- breaking TypeScript has evolved significantly since this package's last update. It is highly probable that complex or modern TypeScript features (e.g., template literal types, conditional types, recursive types, certain utility types) are not correctly or fully converted to PropTypes by this library.
- gotcha The default behavior of PropTypes (runtime validation) and TypeScript (compile-time validation) are fundamentally different. While PropTypes provides runtime checks beneficial for dynamically loaded data or non-TypeScript consumers, TypeScript offers superior developer experience and static analysis.
Install
-
npm install typescript-to-proptypes -
yarn add typescript-to-proptypes -
pnpm add typescript-to-proptypes
Imports
- convertFlowType
import { convertFlowType } from 'typescript-to-proptypes'; - generate
import generate from '@babel/generator';
- Node
import { Node } from 'typescript';
Quickstart
import { createSourceFile, ScriptTarget, SyntaxKind } from 'typescript';
import { convertTypeToPropTypes } from 'typescript-to-proptypes';
import generate from '@babel/generator';
import * as t from '@babel/types';
// Note: The `typescript-to-proptypes` package primarily exposes internal utilities
// that are typically consumed by a Babel plugin. Direct end-user usage for
// a complete conversion from TS source to PropTypes string is complex
// and often requires integrating multiple sub-modules and Babel.
// This example attempts to show a conceptual usage based on its declared purpose
// but may not be a direct 'out-of-the-box' simple call.
const tsSourceCode = `
interface MyProps {
name: string;
age?: number;
isActive: boolean;
items: string[];
data: { id: string; value: any; };
}
interface AnotherType {
id: string;
}
`;
// This is a simplified, illustrative usage. The actual `convertTypeToPropTypes`
// (or similar internal function) would typically operate on a TypeScript AST Node.
// The package's direct exports are not clearly documented for direct consumer use.
// A realistic scenario involves a Babel plugin traversing the AST and calling internal converters.
function getPropTypesFromTs(sourceCode: string, typeName: string): string | null {
try {
const sourceFile = createSourceFile('temp.ts', sourceCode, ScriptTarget.Latest, true);
let typeNode: any = null;
sourceFile.forEachChild(node => {
if ((node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.TypeAliasDeclaration) && node.name.getText(sourceFile) === typeName) {
typeNode = node;
}
});
if (!typeNode) {
console.warn(`Type '${typeName}' not found in source code.`);
return null;
}
// In a real scenario, `convertTypeToPropTypes` would expect a specific TS AST node
// and potentially a full Babel AST context. This is a highly conceptual mapping.
// The `typescript-to-proptypes` library's `convertFlowType` (or similar)
// is more suited for internal AST transformation.
// Since direct `convertTypeToPropTypes` from this package is not exposed for direct high-level use,
// we simulate the expected output structure if it were a direct conversion.
const proptypesAst = t.objectExpression([
t.objectProperty(t.identifier('name'), t.memberExpression(t.identifier('PropTypes'), t.identifier('string'), false)),
t.objectProperty(t.identifier('age'), t.memberExpression(t.identifier('PropTypes'), t.identifier('number'), false)),
t.objectProperty(t.identifier('isActive'), t.memberExpression(t.identifier('PropTypes'), t.memberExpression(t.identifier('PropTypes'), t.identifier('bool'), false), false)),
t.objectProperty(t.identifier('items'), t.callExpression(t.memberExpression(t.identifier('PropTypes'), t.identifier('arrayOf')), [t.memberExpression(t.identifier('PropTypes'), t.identifier('string'), false)])),
t.objectProperty(t.identifier('data'), t.callExpression(t.memberExpression(t.identifier('PropTypes'), t.identifier('shape')), [
t.objectExpression([
t.objectProperty(t.identifier('id'), t.memberExpression(t.identifier('PropTypes'), t.identifier('string'), false)),
t.objectProperty(t.identifier('value'), t.memberExpression(t.identifier('PropTypes'), t.identifier('any'), false))
])
]))
]);
return generate(t.program([t.expressionStatement(proptypesAst)])).code;
} catch (error) {
console.error("Error generating PropTypes:", error);
return null;
}
}
const generatedPropTypes = getPropTypesFromTs(tsSourceCode, 'MyProps');
if (generatedPropTypes) {
console.log('Generated PropTypes for MyProps:\n', generatedPropTypes);
}
/*
Expected (simplified) output for MyProps:
{
name: PropTypes.string,
age: PropTypes.number,
isActive: PropTypes.bool,
items: PropTypes.arrayOf(PropTypes.string),
data: PropTypes.shape({
id: PropTypes.string,
value: PropTypes.any
})
}
*/