Skip to content

Fix typescript compiler nested types. #2070

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,21 @@ describe('Test Typescript component metadata generation', () => {
});
}
);

test(
'Nested props to any', () => {
expect(
R.path([
'TypeScriptComponent',
'props',
'nested',
'type',
'value',
'nested',
'name'
], metadata)).toBe('any')
}
)
});

describe('Test component comments', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Needs to export types if not in a d.ts file or if any import is present in the d.ts
import React from 'react';


type Nested = {
nested: Nested;
}

export type TypescriptComponentProps = {
children?: React.ReactNode;
id?: string;
Expand Down Expand Up @@ -35,6 +40,8 @@ export type TypescriptComponentProps = {
setProps?: (props: Record<string, any>) => void;
className?: string;
style?: any;

nested?: Nested;
};

export type WrappedHTMLProps = {
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
`dangerously_allow_html=True` + `mathjax=True` works in some cases, and in some cases not.
- [#2047](https://github.com/plotly/dash/pull/2047) Fix bug [#1979](https://github.com/plotly/dash/issues/1979) in which `DASH_DEBUG` as enviroment variable gets ignored.
- [#2065](https://github.com/plotly/dash/pull/2065) Fix bug [#2064](https://github.com/plotly/dash/issues/2064) rendering of `dcc.Dropdown` with a value but no options.
- [#2070](https://github.com/plotly/dash/pull/2070) Fix bug [#2066](https://github.com/plotly/dash/issues/2066) nested types triggering maximum call stack error when building typescript components.

### Changed

Expand Down
41 changes: 32 additions & 9 deletions dash/extract-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ const PRIMITIVES = [
'node'
];

// These types take too long to parse because of heavy nesting.
const BANNED_TYPES = [
'Document',
'ShadowRoot',
'ChildNode',
'ParentNode',
];
const unionSupport = PRIMITIVES.concat('boolean', 'Element');

const reArray = new RegExp(`(${unionSupport.join('|')})\\[\\]`);
Expand Down Expand Up @@ -236,9 +243,10 @@ function gatherComponents(sources, components = {}) {
}))
});

const getUnion = (typeObj, propObj) => {
const getUnion = (typeObj, propObj, parentType) => {
let name = 'union',
value;

// Union only do base types
value = typeObj.types
.filter(t => {
Expand All @@ -253,7 +261,7 @@ function gatherComponents(sources, components = {}) {
isArray(checker.typeToString(t))
);
})
.map(t => getPropType(t, propObj));
.map(t => getPropType(t, propObj, parentType));

if (!value.length) {
name = 'any';
Expand Down Expand Up @@ -282,17 +290,19 @@ function gatherComponents(sources, components = {}) {
return propName;
};

const getPropType = (propType, propObj) => {
const getPropType = (propType, propObj, parentType = null) => {
// Types can get namespace prefixes or not.
let name = checker.typeToString(propType).replace(/^React\./, '');
let value;
const raw = name;

const newParentType = (parentType || []).concat(raw)

if (propType.isUnion()) {
if (isUnionLiteral(propType)) {
return {...getEnum(propType), raw};
} else if (raw.includes('|')) {
return {...getUnion(propType, propObj), raw};
return {...getUnion(propType, propObj, newParentType), raw};
}
}

Expand All @@ -318,28 +328,40 @@ function gatherComponents(sources, components = {}) {
const [nodeType] = checker.getTypeArguments(propType);

if (nodeType) {
value = getPropType(nodeType, propObj);
value = getPropType(
nodeType, propObj, newParentType,
);
} else {
// Not sure, might be unsupported here.
name = 'array';
}
}
} else if (
BANNED_TYPES.includes(name) ||
(parentType && parentType.includes(name))
) {
console.error(`Warning nested type: ${name}`);
name = 'any';
} else {
name = 'shape';
// If the type is declared as union it will have a types attribute.
if (propType.types && propType.types.length) {
if (isUnionLiteral(propType)) {
return {...getEnum(propType), raw};
}
return {...getUnion(propType, propObj), raw};
return {
...getUnion(propType, propObj, newParentType),
raw
};
}

value = getProps(
checker.getPropertiesOfType(propType),
propObj,
[],
{},
true
true,
newParentType,
);
}
}
Expand Down Expand Up @@ -543,7 +565,8 @@ function gatherComponents(sources, components = {}) {
propsObj,
baseProps = [],
defaultProps = {},
flat = false
flat = false,
parentType = null,
) => {
const results = {};

Expand Down Expand Up @@ -571,7 +594,7 @@ function gatherComponents(sources, components = {}) {
required,
defaultValue
};
const type = getPropType(propType, propsObj);
const type = getPropType(propType, propsObj, parentType);
// root object is inserted as type,
// otherwise it's flat in the value prop.
if (!flat) {
Expand Down