diff --git a/README.md b/README.md index 4df874c..4c36569 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ class MyComponent extends React.Component { ```tsx type MyComponentProps = { prop1: string; - prop2: number | undefined; + prop2?: number; } type MyComponentState = { diff --git a/src/transforms/react-js-make-props-and-state-transform.ts b/src/transforms/react-js-make-props-and-state-transform.ts index 830275f..aacf6f4 100644 --- a/src/transforms/react-js-make-props-and-state-transform.ts +++ b/src/transforms/react-js-make-props-and-state-transform.ts @@ -222,16 +222,23 @@ export function reactJSMakePropsAndStateInterfaceTransformFactoryFactory(typeChe console.warn('Bad value for propType', name, 'at', propertyAssignment.getStart()); return result; } - const typeValue = getTypeFromReactPropTypeExpression(propertyAssignment.initializer); // Ignore children, React types have it if (propertyAssignment.name.getText() === 'children') { return result; } + + // Ignore children, React types have it + if (propertyAssignment.name.getText() === 'children') { + return result; + } + + const typeValue = getTypeFromReactPropTypeExpression(propertyAssignment.initializer); + const isOptional = isPropTypeOptional(propertyAssignment.initializer); const propertySignature = ts.createPropertySignature( [], name, - undefined, + isOptional ? ts.createToken(ts.SyntaxKind.QuestionToken): undefined, typeValue, undefined, ); @@ -291,19 +298,16 @@ export function reactJSMakePropsAndStateInterfaceTransformFactoryFactory(typeChe } else { result = ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); } + return result; + } - if (!/\.isRequired/.test(text)) { - return makeTypeNodeOptional(result); - } else { - return result; - } - - function makeTypeNodeOptional(node: ts.TypeNode) { - return ts.createUnionOrIntersectionTypeNode(ts.SyntaxKind.UnionType, [ - node, - ts.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword) - ]); - } + /** + * Decide if node is optional + * @param node React propTypes member node + */ + function isPropTypeOptional(node: ts.PropertyAccessExpression) { + const text = node.getText().replace(/React\.PropTypes\./, ''); + return !/\.isRequired/.test(text) } }; }; diff --git a/test/react-js-make-props-and-state-transform/static-proptypes-many-props/output.tsx b/test/react-js-make-props-and-state-transform/static-proptypes-many-props/output.tsx index 89c5602..5607e07 100644 --- a/test/react-js-make-props-and-state-transform/static-proptypes-many-props/output.tsx +++ b/test/react-js-make-props-and-state-transform/static-proptypes-many-props/output.tsx @@ -1,15 +1,15 @@ import * as React from 'react'; export default class MyComponent extends React.Component<{ - any: any | undefined; - array: any[] | undefined; - bool: boolean | undefined; - func: ((...args: any[]) => any) | undefined; - number: number | undefined; - object: object | undefined; - string: string | undefined; - node: (number | string | JSX.Element) | undefined; - element: JSX.Element | undefined; + any?: any; + array?: any[]; + bool?: boolean; + func?: (...args: any[]) => any; + number?: number; + object?: object; + string?: string; + node?: number | string | JSX.Element; + element?: JSX.Element; anyRequired: any; arrayRequired: any[]; boolRequired: boolean;