From 23fd00e413c1af5b8a0d0e5fee37e4eb300463bd Mon Sep 17 00:00:00 2001 From: Mohsen Azimi Date: Sun, 16 Jul 2017 16:00:21 -0700 Subject: [PATCH] Use question mark token for optional props --- README.md | 2 +- ...react-js-make-props-and-state-transform.ts | 36 ++++++++++++------- .../static-proptypes-many-props/output.tsx | 18 +++++----- 3 files changed, 33 insertions(+), 23 deletions(-) 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 826f9d3..1018f70 100644 --- a/src/transforms/react-js-make-props-and-state-transform.ts +++ b/src/transforms/react-js-make-props-and-state-transform.ts @@ -222,8 +222,21 @@ export function reactJSMakePropsAndStateInterfaceTransformFactoryFactory(typeChe console.warn('Bad value for propType', name, 'at', propertyAssignment.getStart()); return result; } + + // Ignore children, React types have it + if (propertyAssignment.name.getText() === 'children') { + return result; + } + const typeValue = getTypeFromReactPropTypeExpression(propertyAssignment.initializer); - const propertySignature = ts.createPropertySignature([], name, undefined, typeValue, undefined); + const isOptional = isPropTypeOptional(propertyAssignment.initializer); + const propertySignature = ts.createPropertySignature( + [], + name, + isOptional ? ts.createToken(ts.SyntaxKind.QuestionToken): undefined, + typeValue, + undefined, + ); result.members.push(propertySignature) return result; }, ts.createTypeLiteralNode([])); @@ -280,19 +293,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 beaa5e4..6551123 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;