We’ve just finished migrating to TS 3.9, and the 4.0 version is already here!
In this article, I’ll go over everything that’s just been released as part of TypeScript 4.0.
I’ll only cover the language features. I might write additional posts to cover what’s also coming regarding editor productivity, performance, and bug fixes.
Class property inference from constructors
tsc is configured in
noImplicitAny mode, the following TS code doesn’t compile:
Now that this PR has been merged and thus, as of TS 4.0, the code above will compile and TypeScript will infer the type of
x to be
string | boolean.
This is one more case where TypeScript’s type inference will help us out!
Short-circuiting assignment operators
It aims to combine logical operators and assignment expressions. Combined with nullish coalescing, which we’ve got since TS 3.7, we will be able to write more condensed code.
Here’s an example given in the proposal:
obj1.obj2.obj3.x ??= 42;
And the same code without those new short-circuiting operators:
obj1.obj2.obj3.x = obj1.obj2.obj3.x ?? 42;
As you can see, with support for this, we would have an even more expressive language, and we’d be able to combine checks and assignments, which would be great.
As mentioned by Daniel Rosenwasser, we’d get one such operator for each of the logical operators, thus:
LeftHandSideExpression &&= AssignmentExpression LeftHandSideExpression ||= AssignmentExpression LeftHandSideExpression ??= AssignmentExpression
Corresponding to what we can currently do with:
LeftHandSideExpression && (LeftHandSideExpression = AssignmentExpression) LeftHandSideExpression || (LeftHandSideExpression = AssignmentExpression) LeftHandSideExpression ?? (LeftHandSideExpression = AssignmentExpression)
Allow unknown on catch clause bindings
Currently, if you try to add a type annotation to a catch clause, the compiler complains:
The code above does not compile and it raises the following error:
TS1196: Catch clause variable cannot have a type annotation
At this point, we simply can’t add a type annotation to a catch clause, which is rather sad from a type safety perspective. The problem is that the errors are always considered to be
any, which lets us do anything with the object within the catch block.
This behavior is simply due to the fact that, originally, the
unknown keyword didn’t exist. But now that it does, it would make much more sense to use it here.
As pointed out in the comments of this proposal, we could get a new strict flag to let us enforce this by default (i.e., make all catch clause errors to be of type unknown). This would force us to correctly check the type before making use of it within the block.
This is one improvement that I’m really interested about!
Variadic Tuple Types
Barbaric name for an awesome new feature. If you don’t know about tuples yet, go learn about those first.
I’m not the biggest fan of tuples (I generally prefer objects/custom types), but sometimes they can indeed prove useful, for instance while writing tests (or type definitions for weird libraries like React :p).
TypeScript 4.0 improves type inference and now allows to correctly type functions dealing with tuples.
First of all, it now supports generics when defining tuple types, allowing them to use generic types defined on a function for tuple elements. As the release notes state, this means that we can represent higher-order operations on tuples and arrays even when we don’t know the actual types we’re operating over.
The release notes include a few examples:
As you can see above, the
tail function returns an array, or elements of type
T. That code is simple to write/understand, which is awesome. Thanks to this new feature, you can see that
r2 are correctly typed.
The other improvement is that spread elements can now appear anywhere in a tuple; not just at the end:
With TS 3.9.x and earlier, couldn’t compile. With TS 4.0, we will be able to do this and the compiler will happily flatten the spreads, wherever they are positioned.
As explained in the release notes, by combining those two features, we can now better type things like the
These new type inference improvements will have a great impact on the quality of our code and I can’t wait to use those in production.
Check out the complete release notes for more details. For instance, they also cover how this will improve use cases like function composition and partial argument application.
Labeled Tuple Elements
Another proposal, introduced by Brian Kim, aims to give us the capability of defining labels for tuple elements.
Currently, tuples are declared like this:
// length, count type Segment = \[number, number\];
Since we can’t assign labels to the tuple elements, the simplest (but really ugly) solution is to rely on comments to remind us of what each element corresponds to.
The other solution (cleaner) is to use custom types that have more useful names. Still, there’s room for improvement.
Some languages such as C# and Python for instance support this.
If this gets added to the language, then we would be able to create more expressive tuples much more simply:
type Segment = [length: number, count: number];
Here, by taking a look at the tuple, we directly know what each number corresponds to.
This would be really useful to clearly understand what tuples are composed of. In addition, as mentioned in the proposal, it would also add more expressiveness to APIs that manipulate/return tuples.
As stated by Daniel Rosenwasser, tuple element names won’t enforce anything in the type system; they’ll exist purely to communicate intent.
Adapt TypeScript’s support for React
Just like TypeScript, React moves crazy fast.
Next to that, support for custom JSX factories will land in TS 4.0, allowing us to customize the fragment factory through the
jsxFragmentFactory option. Check out the release notes and the following PR for details about this.
A few breaking changes are planned with TS 4.0:
- lib.d.ts has changed (DOM types have been adapted), meaning that we could face some new compilations errors when upgrading to this new release. For one, the
document.originproperty, which has been obsolete for quite a while, has been removed
- Overriding accessors with properties (or vice versa) is now considered as an error in all cases. Previously is only raised an error when
useDefineForClassfieldswas used. So if you have derived classes that override getters/setters of the base class, then you’ll have compilation errors with TS 4.0. Check out the PR for details
- With TS 4.0, when in
strictNullChecksmode (i.e., always, right??!), the operand of the
deleteoperator MUST be
neveror be optional (i.e., containing
undefined); otherwise, the code doesn’t compile. Check out the PR for details
The old factory functions for producing TS AST nodes has been deprecated since a new node factory API is being introduced by TS 4.0.
This shouldn’t be an issue for the vast majority of projects.
In this article, I’ve shared what’s new and shiny with TypeScript 4.0.
This amazing language continues to evolve at lightning speed.
Can’t wait to use this in production!
Hello everyone! I'm Sébastien Dubois. I'm an author, founder, and CTO. I write books and articles about software development & IT, personal knowledge management, personal organization, and productivity. I also craft lovely digital products 🚀
If you've enjoyed this article and want to read more like this, then become a subscriber, check out my Obsidian Starter Kit, the PKM Library and my collection of books about software development 🔥.
You can follow me on Twitter 🐦
If you want to discuss, then don't hesitate to join the Personal Knowledge Management community or the Software Crafters community.