When To Use .ts And .tsx File Extensions

When TypeScript released version 1.0 in 2014, it didn't include support for JSX syntax. At the time, React was still a young project that had not yet grown into the huge name it is today. So there was little incentive for the TypeScript team to include functionality for a seemingly niche use-case.

Regardless, this made things challenging – if not impossible – for React developers that wanted to add TypeScript to their projects. The only alternative was to use the non-JSX syntax for React: React.createElement. But this quickly gets cumbersome and was ultimately a showstopper for many React developers.

Eventually, over a year later, TypeScript version 1.6 launched support for JSX and the introduction of a new file extension: .tsx.

The new file extension was necessary because of a design decision made around typecasting. Prior to 1.6 the only way to cast a value to a different type was like this:

```tsx
const x: number = <any>foo
```

This is a problem for supporting JSX since <any> is the exact same syntax used for instantiating a JSX element. To solve this, TypeScript 1.6 also introduced a new default way to typecast with the as operator:

```tsx
const x: number = foo as any
```

This syntax is equivalent to the <any> version and doesn't clash with JSX syntax.

So if we have a compatible syntax, why do we need the .tsx file extension? Well, if a file is using JSX then it can't use the angle bracket typecasting syntax since now it's ambiguous if the brackets should be treated as JSX or typecasting. This was an issue for existing projects that were already using angle bracket typecasting.

Instead of making a breaking change and requiring all projects to migrate to the new syntax, the TypeScript team chose instead to add a new file extension: .tsx. This made using JSX entirely opt-in as well as aligned with the similar .jsx file extension used by non-TypeScript React projects.

There are some other nice-to-have benefits from including a new file extension:

  • Bundlers like webpack can run different plugins just for .tsx files
  • Editors can show a different icon for better visual scanning of files
  • Test runners like jest can run a different test environment (eg, jsdom only for .tsx files)
  • Developers can better communicate intent of a file (eg, .tsx files will contain React components)

None of these benefits are mind-blowingly essential but they're nice.

Conclusion

The .tsx file extension exists in part for historical reasons. Today, those historical reasons are not as relevant for projects created after TypeScript added support for JSX in version 1.6.

So if you're not sure, here's how to decide which extension to use:

  • File that include a React component using JSX syntax use .tsx
  • All other files (eg, utility functions, classes, redux reducers, etc) use .ts

If you don't plan on leveraging file extensions for running bundler plugins, or test runner environments you could also stick to using .tsx for all files. This way you don't need to ever make the decision, or rename a file if first decision was the wrong one.