TypeScript developers are a lucky bunch: for us, Christmas comes four times a year when the TypeScript team releases a new beta version. This is our opportunity to try out the latest features. TypeScript 5.0 beta came out on January 26, 2023. Let's take a look at what's new!
Why not TypeScript 4.10?
First, a note on version numbers. With semantic versioning, a change in the major version typically means breaking changes. And the number after 4.9 is 4.10, not 5.0. TypeScript doesn't really do semantic versioning. The whole point of new TypeScript releases is to find (existing) issues in your code. So in that sense, each release contains breaking changes.
Microsoft also counts in decimal. The version after 4.9 is 5.0, not 4.10. This causes some pain every tenth release since many packages on npm declare that they require typescript@4.x
. This can either hold you back on an old version of TypeScript or lead to fragmentation, as I noticed with TypeScript 4.0 back in 2020:
TIL I have five copies of @typescript in node_modules! @orta was there much debate about whether the version after 3.9 was 3.10 or 4.0? In terms of branding and math, I agree it's 4.0. But since so many packages pin tsc@~3, this seems unnecessarily disruptive… pic.twitter.com/FBiAxZBM15
— Dan Vanderkam (@danvdk) October 23, 2020
Why doesn't TypeScript do versioning in the usual way? The definitive answer comes from TypeScript Tech Lead Ryan Cavanaugh:
The trade-off for getting millions of dollars of engineering investment in the TypeScript project is that marketing gets to control version numbers to a certain extent.
So there you go. Every 2.5 years we have to deal with this extra pain. At least marketing didn't decide that the version after 3.1 was 95!
New Errors
Every new version of TypeScript has the potential to surface new errors in your code. As long-time readers of this blog know, the code samples in Effective TypeScript are all type-checked. One of the benefits of this is that when new TS versions come out, I can type-check my book against them. Sometimes I learn that my book is out of date and sometimes I find new bugs in TypeScript.
TypeScript 5.0 didn't surface any new errors in Effective TypeScript. Huzzah! 🎉
There were a few new errors in my work project. All of them involved comparing string|number
to number
:
|
The full code looks like this:
|
Here val
has type string | number
while minVal
and maxVal
have type number
. JavaScript is notoriously eager to coerce types so that operations make sense:
|
Not helpful, JS! TypeScript has always barred comparisons between strings and numbers. Now the noose has tightened just a bit more and you may have to be more explicit about conversions.
Performance
The TypeScript team claims a 10-20% speedup in build times with TypeScript 5.0 beta. I was able to confirm this both on my work project (Delve) and in running literate-ts against Effective TypeScript:
- literate-ts / Effective TypeScript:
- TS 4.9.5: 194.12s
- TS 5.0-beta: 181.31s (6.6% speedup)
- Delve:
- TS 4.9.5: 46.36s
- TS 5.0-beta: 38.27s (17.5% speedup)
Compiler speed is important and these are both welcome improvements! You can read the release notes for more details on how these speedups were achieved.
const
type parameters
const
type parameters are the one new language feature in this release. These are like as const
but applied on the function declaration, rather than at the call site.
The applications I see for this in my own code are mostly small quality of life wins. For example, my work project has a DropdownList
component that takes a list of options and a selected option. The list of options should be a tuple of string literals, and the selected option should be one of those literals:
|
With TypeScript 5.0 we can move the const
into the declaration of DropdownList
:
|
And drop the as const
at the callsite:
|
If you inspect options
here, you can see that its type is inferred as readonly ("Option A" | "Option B" | "Option C")[]
whereas before it would have been inferred as readonly string[]
. Nice! If you factor the list of options out into a variable, though, the context will be lost and you'll be back to using as const
.
What else is this useful for? Back in 2020 I talked about the tuple
helper function:
|
What if we use a const
type parameter on tuple
? Interestingly, it becomes a sort of "deep tuple":
|
Is this useful? Maybe. There are always compelling applications of new language features and I'm sure I'm missing some here. Do you have a use for const
type parameters? Let me know in the comments!
Enums are unions
In Effective TypeScript Item 53 ("Prefer ECMAScript Features to TypeScript Features") I discourage using enums since they're not an ECMAScript feature and generally break the mold of how TypeScript relates to JavaScript ("JavaScript + Types").
With TypeScript 5.0, enums become a little more sane. Whereas this was OK in TypeScript 4.9:
|
It's an error in TypeScript 5.0:
|
So are enums OK now? As it turns out, the newfound sanity is only surface deep:
|
TypeScript enums are complicated and problematic. While they become slightly saner with TypeScript 5.0, I still say "avoid them."
Conclusions
There are more changes in the new release than what I've written about here. Check out the release notes for full details. With any luck, a release candidate (RC) will arrive on February 28th and the final cut of TypeScript 5.0 will be out on March 14th.