diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 57c50e460f74f..c3e6087839bd9 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -869,10 +869,6 @@ namespace ts.codefix { return { kind: ImportFixKind.PromoteTypeOnly, typeOnlyAliasDeclaration }; } - function jsxModeNeedsExplicitImport(jsx: JsxEmit | undefined) { - return jsx === JsxEmit.React || jsx === JsxEmit.ReactNative; - } - function getSymbolName(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string { const parent = symbolToken.parent; if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken && jsxModeNeedsExplicitImport(compilerOptions.jsx)) { diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index 77fba1707b0e8..d01f2eae5f6d6 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -95,6 +95,7 @@ namespace ts.OrganizeImports { } const typeChecker = program.getTypeChecker(); + const compilerOptions = program.getCompilerOptions(); const jsxNamespace = typeChecker.getJsxNamespace(sourceFile); const jsxFragmentFactory = typeChecker.getJsxFragmentFactory(sourceFile); const jsxElementsPresent = !!(sourceFile.transformFlags & TransformFlags.ContainsJsx); @@ -162,7 +163,7 @@ namespace ts.OrganizeImports { function isDeclarationUsed(identifier: Identifier) { // The JSX factory symbol is always used if JSX elements are present - even if they are not allowed. - return jsxElementsPresent && (identifier.text === jsxNamespace || jsxFragmentFactory && identifier.text === jsxFragmentFactory) || + return jsxElementsPresent && (identifier.text === jsxNamespace || jsxFragmentFactory && identifier.text === jsxFragmentFactory) && jsxModeNeedsExplicitImport(compilerOptions.jsx) || FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile); } } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 016eb35227eda..ccbd9d1c557e9 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -3335,5 +3335,9 @@ namespace ts { }; } + export function jsxModeNeedsExplicitImport(jsx: JsxEmit | undefined) { + return jsx === JsxEmit.React || jsx === JsxEmit.ReactNative; + } + // #endregion } diff --git a/tests/baselines/reference/organizeImports/JsxFactoryUsedJs.ts b/tests/baselines/reference/organizeImports/JsxFactoryUsedJs.ts index 430a5b12cd4d4..74da2f99139e0 100644 --- a/tests/baselines/reference/organizeImports/JsxFactoryUsedJs.ts +++ b/tests/baselines/reference/organizeImports/JsxFactoryUsedJs.ts @@ -6,6 +6,5 @@ import { React, Other } from "react"; // ==ORGANIZED== -import { React } from "react";
; diff --git a/tests/cases/fourslash/organizeImportsReactJsx.ts b/tests/cases/fourslash/organizeImportsReactJsx.ts new file mode 100644 index 0000000000000..38529f1bd0e7a --- /dev/null +++ b/tests/cases/fourslash/organizeImportsReactJsx.ts @@ -0,0 +1,33 @@ +/// + +// @allowSyntheticDefaultImports: true +// @moduleResolution: node +// @noUnusedLocals: true +// @target: es2018 +// @jsx: react-jsx + +// @filename: test.tsx +////import React from 'react'; +////export default () =>
+ +// @filename: node_modules/react/package.json +////{ +//// "name": "react", +//// "types": "index.d.ts", +////} + +// @filename: node_modules/react/index.d.ts +////export = React; +////declare namespace JSX { +//// interface IntrinsicElements { [x: string]: any; } +////} +////declare namespace React {} + +// @filename: node_modules/react/jsx-runtime.d.ts +////import './'; + +// @filename: node_modules/react/jsx-dev-runtime.d.ts +////import './'; + +goTo.file("test.tsx"); +verify.organizeImports(`export default () =>
`); diff --git a/tests/cases/fourslash/organizeImportsReactJsxDev.ts b/tests/cases/fourslash/organizeImportsReactJsxDev.ts new file mode 100644 index 0000000000000..0bf5b4f884867 --- /dev/null +++ b/tests/cases/fourslash/organizeImportsReactJsxDev.ts @@ -0,0 +1,33 @@ +/// + +// @allowSyntheticDefaultImports: true +// @moduleResolution: node +// @noUnusedLocals: true +// @target: es2018 +// @jsx: react-jsxdev + +// @filename: test.tsx +////import React from 'react'; +////export default () =>
+ +// @filename: node_modules/react/package.json +////{ +//// "name": "react", +//// "types": "index.d.ts", +////} + +// @filename: node_modules/react/index.d.ts +////export = React; +////declare namespace JSX { +//// interface IntrinsicElements { [x: string]: any; } +////} +////declare namespace React {} + +// @filename: node_modules/react/jsx-runtime.d.ts +////import './'; + +// @filename: node_modules/react/jsx-dev-runtime.d.ts +////import './'; + +goTo.file("test.tsx"); +verify.organizeImports(`export default () =>
`);