Typescript: Allow JSX without using `.tsx` extension

Created on 20 Mar 2019  路  20Comments  路  Source: microsoft/TypeScript

Search Terms

JSX, TSX, React, extension

Suggestion

I'm creating a new issue because comments in the closed https://github.com/Microsoft/TypeScript/issues/26489 issue are ignored, but it's clear that many people want this.

It's annoying having to use a separate file extension just because you want to use JSX. Not all tooling supports the .tsx extension. It also means you either need to always use .tsx if there's a possibility of JSX usage or you need to keep renaming files when you add JSX to them. Neither are good UX.

I propose deprecating <Type>expr in favor of as (as suggested in https://github.com/Microsoft/TypeScript/issues/26489#issuecomment-452633168). They do the same thing, but as is not conflicting with JSX. No point in having duplicate syntax that does the same thing.

Alternatively, add a compiler flag to disable <Type>expr, which means JSX could be supported for the .ts extension when this compiler flag is used.

Use Cases

Examples

Checklist

My suggestion meets these guidelines:

  • [ ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • [x] This feature would agree with the rest of TypeScript's Design Goals.
Duplicate

Most helpful comment

@bricss This is different. TypeScript (and .ts) is already "non-standard" in the JS sense.

It also doesn't reflect most JSX users opinion about .jsx vs .js. See: https://github.com/airbnb/javascript/pull/985#issuecomment-239145468 (Look at the votes)


The argument from https://github.com/airbnb/javascript/issues/1235#issuecomment-271094968 is:

essentially, .js should only ever be for files that use features of standard JavaScript

But JSX is part of TypeScript. So that argument falls apart in this case.

All 20 comments

Please don't. For a instance 馃憠 https://github.com/airbnb/javascript/issues/1235#issuecomment-271094968

@bricss This is different. TypeScript (and .ts) is already "non-standard" in the JS sense.

It also doesn't reflect most JSX users opinion about .jsx vs .js. See: https://github.com/airbnb/javascript/pull/985#issuecomment-239145468 (Look at the votes)


The argument from https://github.com/airbnb/javascript/issues/1235#issuecomment-271094968 is:

essentially, .js should only ever be for files that use features of standard JavaScript

But JSX is part of TypeScript. So that argument falls apart in this case.

Not all tooling supports the .tsx extension.

A world where half the tools can't figure out what the right way to parse a .ts file on its own is so clearly worse to me than the current world. I'm curious as to what tools can't support .tsx files and why.

@sindresorhus <> assertions are not the only parsing ambiguity. Generic arrow functions also behave differently in .ts vs .tsx:

let fn = <T>(o: T)=> o; // ok in ts parsing error in tsx, <T> is the start of a tag

A world where half the tools can't figure out what the right way to parse a .ts file on its own is so clearly worse to me than the current world. I'm curious as to what tools can't support .tsx files and why.

The cases I've seen are simply that they only considered the .ts extension.

<> assertions are not the only parsing ambiguity. Generic arrow functions also behave differently in .ts vs .tsx:

IMHO, that should be solved regardless of the outcome of this issue. Even with separate extensions, it's weird that TS and TSX works differently in common cases like this. I don't have a solution. I'm hoping smarter people than me can come up with one.

Probably a duplicate of https://github.com/Microsoft/TypeScript/issues/8529. At least that's what I originally wanted as well (but the discussion drifted a little bit away and the title was changed from Make ".tsx" extension optional to Make default JSX mode "react"). So I'm glad this topic is raised again. Thank you.

I think the key problem is <jsx>...</jsx> do not have definite semantic as general purpose language. (compile to React.createElement() is too domain-specific, framework-specific) So it's hard to imagine how jsx could be a part of js standard. This is also apply to TS.

Of coz, there is another problem, whether we allow non-standard feature in .js or .ts extension. Strictly speaking, many .js files today are using "babel language", not js language 馃槀 (and babel now support almost all TS syntax too 馃槝). But such issue is always not a solely tech issue, but a social issue. Remember there are many programmers dislike jsx anyway 馃槄 and don't want jsx "pollute" their js source codes.

@sindresorhus I think smart people did think about this and they did not leave this in because of laziness.

The ambiguity is not easy so solve without looking a lot ahead into the stream trying to interpret <T>(o: T)=> o; as the start of a tag and if that errs, try interpreting as a generic function .. or the other way around ... But either way performance would suffer in both cases.

@hax

compile to React.createElement() is too domain-specific, framework-specific

I agree that compiling to React.createElement is too specific, but supporting JSX isn't just for supporting React. It'd be totally acceptable that I would need to configure what JSX will be compiled for, and I will get an error if it wasn't configured.

.tsx already exists, so there's nothing new here, just unifying the experience. And it doesn't mean tying everything to React!

Since I use .js for all react components it's very natural to use .ts and why can't ts compiler support both .ts and .tsx.

It could be enabled with a flag (maybe a tsxExtension).

By the way, I do not think that enabling and forcing this by default could be a good idea: people developing batch, command line interfaces or back end stuff should not have the risk of outputting jsx related stuff.

This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)

It seems this box shouldn鈥檛 be checked.

@mathiasbynens By default, TypeScript doesn't transform the JSX, so it is correct.

FYI, most editors also need different grammars for syntax highlighting tsx vs ts (because of the aforementioned ambiguities) and key which to use off of the extension by default. For every tool that doesn't work with .tsx there is, at this point, another tool which wouldn't work _without_ .tsx. I'm not the biggest fan of semantic extensions, but it is a workable solution to the ambiguity issue.

@weswigham I think the point of the issue is that we wouldn't need different grammars if we dropped the ambiguities. Flow does not have the <number>expr casting syntax and it handles lambda functions with generics const x = <T>() => <div></div> without issues and alongside React components.

But you're not dropping any ambiguities with this proposal (since .ts already doesn't permit JSX), you're just introducing them.

For your consideration:

let fn = <T>(o: T)=> o;
1 < / T >, o // 2

The above code is syntactically valid TS, and, except for the type parameter and annotation on the lambda, syntactically valid JS. In flow, the above code is also valid... but not like you'd think based on the indentations. <T> is interpreted as a JSX opening tag, which is closed on the following line with some text, followed by a comma indicating _a second let variable with no initializer followed by a comment_.

flow still has the ambiguity - rather than issuing an error, they just greedily assume <T> is a tag if there's a token sequence that can provide a matching end tag (I can't really fault this as there are other ambiguities where we do something similar; but the ambiguity is part of our justification here). There is no "correct" way to parse the above sequence of tokens in the context of JSX. Outside of JSX mode, TS _correctly_ parses this - <T> is a type parameter list, and the second line is "1 less than some regex literal containing 'T>,o' divided by 2" (strange to write, but syntactically valid code). In JSX mode, we usually issue an error on the <T> because we _know_ it's potentially ambiguous, as in this example.

I wasn't aware of this, great example @weswigham, thank you!
Would it be any less ambiguous if there was a hard requirement on JSX tags in .ts files to be wrapped in braces (like prettier does by default)?

const jsxInDotTs = (<span>
  hello
</span>)

An extra brace is still better than not having JSX in .ts at all :)

Please don't open new issues because you didn't like the outcome of prior issues; we cannot sustain a repo where every declined issue just gets re-filed. We read comments in closed issues and are happy to hear additional feedback in #26489

Was this page helpful?
0 / 5 - 0 ratings