180
votes

I just start working on a React project with TypeScript and ask myself what should I do with regular class files? Should I use .ts or .tsx files and then I couldn't find any reason to do not using .tsx file all the times even when it's not a React project!

Is there any reason or specific situation that we shouldn't use .tsx files? if no, why TypeScript team add whole new extension?

5

5 Answers

235
votes

You can use tsx instead of ts with very little difference. tsx obviously allows the usage of jsx tags inside TypeScript, but this introduces some parsing ambiguities that make tsx slightly different. In my experience these differences are not very big:

Type assertions with <> don't work as that is the marker for a jsx tag.

TypeScript has two syntaxes for type assertions. They both do the exact same thing but one is usable in tsx the other is not:

let a: any;
let s = a as string // ok in tsx and ts
let s2 = <string>a // only valid in ts

I would use as instead of <> in ts files as well for consistency. as was actually introduced in TypeScript because <> was not usable in tsx.

Generic arrow functions with no constraint are not parsed correctly

The arrow function below is ok in ts but an error in tsx as <T> is interpreted as the start of a tag in tsx:

 const fn = <T>(a: T) => a

You can get around this either by adding a constraint or not using an arrow function:

 const fn = <T extends any>(a: T) => a
 const fn = <T,>(a: T) => a // this also works but looks weird IMO
 const fn = function<T>(a: T) { return a;}

Note

While you can use tsx instead of ts, I would recommend against it. Convention is a powerful thing, people associate tsx with jsx and will probably be surprised you don't have any jsx tags, best keep developer surprise to a minimum.

While the ambiguities above (although probably not a complete list) are not big they probably played a big part in the decision to use a dedicated file extension for the new syntax in order to keep ts files backward compatible.

66
votes

It's kind of a convention to use x in the end when your JavaScript is in JSX Harmony mode. That is, when this is valid:

doSomething(<div>My div</div>);

However, your file extension doesn't really matter, as long as your pre-processors are aware of your decision (browserify or webpack). I, for one, use .js for all my JavaScript, even when they are React. The same applies for TypeScript, ts/tsx.

EDIT

Now, I would strongly recommend using JSX for Javascript with React syntax and TSX for TypeScript with React because most editors/IDEs will use the extension to enable or not the React syntax. It is also consider it to be more expressive.

9
votes

The reason why .jsx extension was introduced is that JSX is an extension of JS syntax and thus .jsx files don't contain valid JavaScript.

TypeScript follows the same convention by introducing .ts and .tsx extensions. A practical difference is that .tsx don't allow <Type> type assertions because the syntax is in conflict with JSX tags. as Type assertions was introduced as a replacement for <Type> and considered a preferred choice for consistency reasons in both .ts and .tsx. In case the code from .ts is used in .tsx file, <Type> will need to be fixed.

The use of .tsx extension implies that a module is related to React and uses JSX syntax. In case it doesn't, the extension may give false impression about module contents and the role in the project, this is the argument against using .tsx extension by default.

On the other hand, if a file is related to React and has good chances to contain JSX at some point, it can be named as .tsx from the beginning to avoid renaming later.

For instance, utility functions that are used together with React components may involve JSX at any point and thus can be safely use .tsx names, while Redux code structure isn't supposed to use React components directly, can be used and tested apart from React and can use .ts names.

6
votes

I believe with the .tsx files you could use the all JSX (JavaScript XML) code. Whereas in the .ts file you can only use just typescript.

3
votes

.ts files have an <AngleBracket> type assertion syntax which conflicts with the JSX grammar. In order to avoid breaking a ton of people, we use .tsx for JSX, and added the foo as Bar syntax which is allowed in both .ts and .tsx files.

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

And the other is the as-syntax:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

We can use .ts with as-syntax but <string>someValue is cool!