diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index b1cd63ee5b371..d93b37ce1add0 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -2040,8 +2040,22 @@ namespace ts {
}
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
- const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host,
- sourceFile.languageVariant === LanguageVariant.JSX && options.jsx === JsxEmit.Preserve ? ".jsx" : ".js");
+ // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
+ // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
+ // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
+ let extension = ".js";
+ if (options.jsx === JsxEmit.Preserve) {
+ if (isSourceFileJavaScript(sourceFile)) {
+ if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
+ extension = ".jsx";
+ }
+ }
+ else if (sourceFile.languageVariant === LanguageVariant.JSX) {
+ // TypeScript source file preserving JSX syntax
+ extension = ".jsx";
+ }
+ }
+ const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
const emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
diff --git a/tests/baselines/reference/jsxPreserveWithJsInput.js b/tests/baselines/reference/jsxPreserveWithJsInput.js
new file mode 100644
index 0000000000000..2cc59ffa355df
--- /dev/null
+++ b/tests/baselines/reference/jsxPreserveWithJsInput.js
@@ -0,0 +1,29 @@
+//// [tests/cases/compiler/jsxPreserveWithJsInput.ts] ////
+
+//// [a.js]
+
+var elemA = 42;
+
+//// [b.jsx]
+var elemB = {"test"};
+
+//// [c.js]
+var elemC = {42};
+
+//// [d.ts]
+var elemD = 42;
+
+//// [e.tsx]
+var elemE = {true};
+
+
+//// [a.js]
+var elemA = 42;
+//// [b.jsx]
+var elemB = {"test"};
+//// [c.js]
+var elemC = {42};
+//// [d.js]
+var elemD = 42;
+//// [e.jsx]
+var elemE = {true};
diff --git a/tests/baselines/reference/jsxPreserveWithJsInput.symbols b/tests/baselines/reference/jsxPreserveWithJsInput.symbols
new file mode 100644
index 0000000000000..6ad2f6148757f
--- /dev/null
+++ b/tests/baselines/reference/jsxPreserveWithJsInput.symbols
@@ -0,0 +1,27 @@
+=== tests/cases/compiler/a.js ===
+
+var elemA = 42;
+>elemA : Symbol(elemA, Decl(a.js, 1, 3))
+
+=== tests/cases/compiler/b.jsx ===
+var elemB = {"test"};
+>elemB : Symbol(elemB, Decl(b.jsx, 0, 3))
+>b : Symbol(unknown)
+>b : Symbol(unknown)
+
+=== tests/cases/compiler/c.js ===
+var elemC = {42};
+>elemC : Symbol(elemC, Decl(c.js, 0, 3))
+>c : Symbol(unknown)
+>c : Symbol(unknown)
+
+=== tests/cases/compiler/d.ts ===
+var elemD = 42;
+>elemD : Symbol(elemD, Decl(d.ts, 0, 3))
+
+=== tests/cases/compiler/e.tsx ===
+var elemE = {true};
+>elemE : Symbol(elemE, Decl(e.tsx, 0, 3))
+>e : Symbol(unknown)
+>e : Symbol(unknown)
+
diff --git a/tests/baselines/reference/jsxPreserveWithJsInput.types b/tests/baselines/reference/jsxPreserveWithJsInput.types
new file mode 100644
index 0000000000000..7f4ed6daa2b98
--- /dev/null
+++ b/tests/baselines/reference/jsxPreserveWithJsInput.types
@@ -0,0 +1,35 @@
+=== tests/cases/compiler/a.js ===
+
+var elemA = 42;
+>elemA : number
+>42 : number
+
+=== tests/cases/compiler/b.jsx ===
+var elemB = {"test"};
+>elemB : any
+>{"test"} : any
+>b : any
+>"test" : string
+>b : any
+
+=== tests/cases/compiler/c.js ===
+var elemC = {42};
+>elemC : any
+>{42} : any
+>c : any
+>42 : number
+>c : any
+
+=== tests/cases/compiler/d.ts ===
+var elemD = 42;
+>elemD : number
+>42 : number
+
+=== tests/cases/compiler/e.tsx ===
+var elemE = {true};
+>elemE : any
+>{true} : any
+>e : any
+>true : boolean
+>e : any
+
diff --git a/tests/cases/compiler/jsxPreserveWithJsInput.ts b/tests/cases/compiler/jsxPreserveWithJsInput.ts
new file mode 100644
index 0000000000000..f229e40a55012
--- /dev/null
+++ b/tests/cases/compiler/jsxPreserveWithJsInput.ts
@@ -0,0 +1,18 @@
+// @outdir: out
+// @jsx: preserve
+// @allowjs: true
+
+// @filename: a.js
+var elemA = 42;
+
+// @filename: b.jsx
+var elemB = {"test"};
+
+// @filename: c.js
+var elemC = {42};
+
+// @filename: d.ts
+var elemD = 42;
+
+// @filename: e.tsx
+var elemE = {true};