Every three months we get a new TypeScript release and TypeScript 5.1 landed on June 1, 2023. This release has a few interesting new features, but by far the most noticeable changes are performance improvements and error message ergonomics. Let's take a look!
Performance Improvements
When you hear "new TypeScript version", the natural tendency is to think about new language features. But what would you be more excited about: an exciting new feature like template literal types or a 10% faster compiler? Sorry, you can't have both!
The TypeScript team takes compiler performance incredibly seriously and every single set of release notes includes a few performance optimizations. A recent theme has been improving build times for projects that use complex libraries like Material-UI. The 5.1 release includes several optimizations that add up to a big win.
As readers of this blog may recall, Effective TypeScript is itself type-checked using literate-ts. The idea is that when new versions of TypeScript come out, I can quickly check whether any of the hundreds of code samples in the book produce new and unexpected errors. This is a great confidence booster that my book still matches reality, but it also means that Effective TypeScript can serve as a good gauge of what's changed between releases.
First let's look at performance:
- Checking Effective TypeScript (TS 5.0.4): 180.6s average
- Checking Effective TypeScript (TS 5.1.3): 170.9s average
That's about a 5% speedup. Not bad!
Improved Error Messages
literate-ts is very sensitive to how error messages and types display. TypeScript 5.1 includes a nice change in how type errors on return
statements are displayed that didn't make it into the release notes. In previous versions of TypeScript, if you returned an expression of the wrong type, you'd get the dreaded red squiggles under both the return
keyword and the entire expression. For multiline expressions, this could be a lot of red!
With TypeScript 5.1, the red squiggles only appear under the return
keyword:
This is less distracting and makes it easier for you to inspect your code to find the source of the error. Not a huge change, but a nice win nonetheless. Next time you're debugging a type error in a return
statement, thank Mateusz Burzyński for the change!
New Errors
Upgrading TypeScript often uncovers existing mistakes in your code and TS 5.1 was no exception. There was one new error that came up in a few of my projects.
TypeScript has long flagged duplicate keys in object literals:
|
But if you used computed keys, this error would go away:
|
With TS 5.1, this is an error:
|
This check only occurs for single-valued literal types.
Notes on other changes
The "headline" features in the official release notes for TS 5.1 are mostly niche changes that won't affect many users immediately. Here's a quick rundown:
- Easier Implicit Returns for undefined-Returning Functions I've never personally run across a function that was declared to return
undefined
rather thanvoid
. But if you work with such functions, your life gets easier with TS 5.1. - Unrelated Types for Getters and Setters This seems like a bad idea though as the CSS example in the release notes makes clear, this is an established pattern in the wild that TypeScript needs to model. I tend to avoid getters and setters (and classes in general). This relates to Effective TypeScript's Item 29: Be Liberal in What You Accept and Strict in What You Produce.
- Decoupled Type-Checking Between JSX Elements and JSX Tag Types This seems quite in the weeds, but the gist is that it's future-proofing for async React components, which may land sometime in the future. When these eventually land, we'll be happy that TypeScript supports them out of the box.
I was extremely excited about one other change in the TypeScript 5.1 RC that sadly got cut for the release: a "move to existing file" refactor. There's a nice video of this in action in the RC release notes. This has been a long-standing and much-upvoted feature request. You can move a symbol to a new file, but not to an existing file.
I have a workaround, but it's a bit gross. Say you want to move a symbol to an existing file src/utils/my-utils.ts
. Instead, move it to a new file src/utils/new-file.ts
. This will update all the imports for the symbol to point to the new file. Then cut/paste the definition of your symbol into my-utils.ts
, delete new-file.ts
and run a big Find/Replace to update all the imports:
|
Like I said, gross! Hopefully this feature lands more permanently in TypeScript 5.2.
Conclusions
TypeScript 5.1 is not a major release when it comes to new language features, but it does include some performance wins, it may catch some new errors in your project, and it lays the groundwork for more changes in the future. Keep your eyes out for the TypeScript 5.2 beta which should be landing any day now and looks to have some exciting new features.