Skip to content
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
9 changes: 8 additions & 1 deletion packages/core/integration-tests/test/ts-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ describe('typescript types', function () {
index.ts:
export * from "./ErrorBoundary";
export * from "./ErrorBoundaryContext";
export * from "./Component";

foo.js:
import {baz} from './baz';
Expand Down Expand Up @@ -495,6 +496,11 @@ describe('typescript types', function () {
);
}
}

Component.tsx:
export function Foo() {
return <h1>Foo</h1>;
}
`;

let b = await bundle(path.join(dir, '/index.ts'), {
Expand All @@ -505,12 +511,13 @@ describe('typescript types', function () {
let output = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
assert.equal(
output,
`import { Context, Component, PropsWithChildren, ProviderProps, FunctionComponentElement } from "react";
`import { Context, Component, PropsWithChildren, ProviderProps, FunctionComponentElement, JSX } from "react";
export type ErrorBoundaryContextType = {};
export const ErrorBoundaryContext: Context<ErrorBoundaryContextType>;
export class ErrorBoundary extends Component<PropsWithChildren> {
render(): FunctionComponentElement<ProviderProps<ErrorBoundaryContextType>>;
}
export function Foo(): JSX.Element;

//# sourceMappingURL=types.d.ts.map
`,
Expand Down
35 changes: 24 additions & 11 deletions packages/transformers/typescript-types/src/collect.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type {TSModuleGraph} from './TSModuleGraph';

import nullthrows from 'nullthrows';
import ts from 'typescript';
import ts, {type EntityName} from 'typescript';
import {TSModule} from './TSModule';
import {getExportedName, isDeclaration} from './utils';

Expand Down Expand Up @@ -91,16 +91,9 @@ export function collect(
ts.isStringLiteral(node.argument.literal)
) {
let local = `$$parcel$import$${moduleGraph.syntheticImportCount++}`;
if (node.qualifier) {
currentModule.addImport(
local,
node.argument.literal.text,
node.qualifier.text,
);
} else {
currentModule.addImport(local, node.argument.literal.text, '*');
}
return factory.createTypeReferenceNode(local, node.typeArguments);
let [specifier, entity] = getImportName(node.qualifier, local, factory);
currentModule.addImport(local, node.argument.literal.text, specifier);
return factory.createTypeReferenceNode(entity, node.typeArguments);
}

// Handle `export default name;`
Expand Down Expand Up @@ -142,3 +135,23 @@ export function collect(

return ts.visitNode(sourceFile, visit);
}

// Traverse down an EntityName to the root identifier. Return that to use as the named import specifier,
// and collect the remaining parts into a new QualifiedName with the local replacement at the root.
// import('react').JSX.Element => import {JSX} from 'react'; JSX.Element
function getImportName(
qualifier: ?EntityName,
local: string,
factory: typeof ts,
) {
if (!qualifier) {
return ['*', factory.createIdentifier(local)];
}

if (qualifier.kind === ts.SyntaxKind.Identifier) {
return [qualifier.text, factory.createIdentifier(local)];
}

let [name, entity] = getImportName(qualifier.left, local, factory);
return [name, factory.createQualifiedName(entity, qualifier.right)];
}