diff --git a/src/parser.ts b/src/parser.ts index 772857a..d21322e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -376,15 +376,21 @@ export function parseFromProgram( } } - let type = declaration + const symbolType = declaration ? // The proptypes aren't detailed enough that we need all the different combinations // so we just pick the first and ignore the rest - checker.getTypeAtLocation(declaration) + checker.getTypeOfSymbolAtLocation(symbol, declaration) : // The properties of Record<..., ...> don't have a declaration, but the symbol has a type property ((symbol as any).type as ts.Type); // get `React.ElementType` from `C extends React.ElementType` - const baseConstraintOfType = checker.getBaseConstraintOfType(type); - type = baseConstraintOfType === undefined ? type : baseConstraintOfType; + const declaredType = + declaration !== undefined ? checker.getTypeAtLocation(declaration) : undefined; + const baseConstraintOfType = + declaredType !== undefined ? checker.getBaseConstraintOfType(declaredType) : undefined; + const type = + baseConstraintOfType !== undefined && baseConstraintOfType !== declaredType + ? baseConstraintOfType + : symbolType; if (!type) { throw new Error('No types found'); diff --git a/test/union-props/input.d.ts b/test/union-props/input.d.ts new file mode 100644 index 0000000..05c56d1 --- /dev/null +++ b/test/union-props/input.d.ts @@ -0,0 +1,21 @@ +import * as React from 'react'; + +export interface BaseProps { + value?: unknown; +} + +export interface StandardProps extends BaseProps { + variant?: 'standard'; +} + +export interface OutlinedProps extends BaseProps { + variant: 'outlined'; +} + +export interface FilledProps extends BaseProps { + variant: 'filled'; +} + +export type TextFieldProps = StandardProps | OutlinedProps | FilledProps; + +export default function TextField(props: TextFieldProps): JSX.Element; diff --git a/test/union-props/input.js b/test/union-props/input.js new file mode 100644 index 0000000..65c2d58 --- /dev/null +++ b/test/union-props/input.js @@ -0,0 +1,11 @@ +import * as React from 'react'; + +export default function TextField(props) { + const { value, variant } = props; + + return ( + + {variant}: + + ); +} diff --git a/test/union-props/output.js b/test/union-props/output.js new file mode 100644 index 0000000..77872fa --- /dev/null +++ b/test/union-props/output.js @@ -0,0 +1,19 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; + +function TextField(props) { + const { value, variant } = props; + + return ( + + {variant}: + + ); +} + +TextField.propTypes = { + value: PropTypes.any, + variant: PropTypes.oneOf(['filled', 'outlined', 'standard']), +}; + +export default TextField; diff --git a/test/union-props/output.json b/test/union-props/output.json new file mode 100644 index 0000000..cc3e480 --- /dev/null +++ b/test/union-props/output.json @@ -0,0 +1,34 @@ +{ + "type": "ProgramNode", + "body": [ + { + "type": "ComponentNode", + "name": "TextField", + "types": [ + { + "type": "PropTypeNode", + "name": "variant", + "propType": { + "type": "UnionNode", + "types": [ + { "type": "UndefinedNode" }, + { "type": "LiteralNode", "value": "\"standard\"" }, + { "type": "LiteralNode", "value": "\"outlined\"" }, + { "type": "LiteralNode", "value": "\"filled\"" } + ] + }, + "filenames": {} + }, + { + "type": "PropTypeNode", + "name": "value", + "propType": { + "type": "UnionNode", + "types": [{ "type": "UndefinedNode" }, { "type": "AnyNode" }] + }, + "filenames": {} + } + ] + } + ] +}