Skip to content
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

Allow JSX without using .tsx extension #30503

Closed
4 of 5 tasks
sindresorhus opened this issue Mar 20, 2019 · 20 comments
Closed
4 of 5 tasks

Allow JSX without using .tsx extension #30503

sindresorhus opened this issue Mar 20, 2019 · 20 comments
Labels
Duplicate An existing issue was already created

Comments

@sindresorhus
Copy link

sindresorhus commented Mar 20, 2019

Search Terms

JSX, TSX, React, extension

Suggestion

I'm creating a new issue because comments in the closed #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 #26489 (comment)). 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
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@bricss
Copy link

bricss commented Mar 20, 2019

Please don't. For a instance 👉 airbnb/javascript#1235 (comment)

@sindresorhus
Copy link
Author

sindresorhus commented Mar 20, 2019

@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: airbnb/javascript#985 (comment) (Look at the votes)


The argument from airbnb/javascript#1235 (comment) 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.

@DanielRosenwasser
Copy link
Member

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.

@dragomirtitian
Copy link
Contributor

@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

@sindresorhus
Copy link
Author

sindresorhus commented Mar 20, 2019

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.

@sindresorhus
Copy link
Author

sindresorhus commented Mar 20, 2019

<> 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.

@donaldpipowitch
Copy link
Contributor

Probably a duplicate of #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.

@hax
Copy link

hax commented Mar 20, 2019

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.

@dragomirtitian
Copy link
Contributor

dragomirtitian commented Mar 20, 2019

@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.

@Schniz
Copy link

Schniz commented Mar 20, 2019

@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!

@pavan-shipmnts
Copy link

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.

@OctoD
Copy link

OctoD commented Mar 20, 2019

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.

@mathiasbynens
Copy link

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

It seems this box shouldn’t be checked.

@sindresorhus
Copy link
Author

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

@weswigham
Copy link
Member

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.

@niieani
Copy link

niieani commented Mar 21, 2019

@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.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Mar 21, 2019

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

@weswigham
Copy link
Member

weswigham commented Mar 21, 2019

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.

@niieani
Copy link

niieani commented Mar 22, 2019

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 :)

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 25, 2019
@RyanCavanaugh
Copy link
Member

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

@microsoft microsoft locked as resolved and limited conversation to collaborators Mar 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests