News Blog

Stay tuned as the company news with our expert team innovations in latest technology.

What’s new in TypeScript 4.9


If you’re not familiar with TypeScript, it’s a language that builds on JavaScript by adding types and type-checking. Types can describe things like the shapes of our objects, how functions can be called, and whether a property can be null or undefined. TypeScript can check these types to make sure you’re not making mistakes in your programs so you can code with confidence. It can also power other tooling like auto-completion, go-to-definition, and refactorings in the editor. In fact, if you’ve used an editor like Visual Studio or VS Code for JavaScript, that same experience is already powered by TypeScript!

To get started with TypeScript 4.9, you can get it through NuGet, or use npm with the following command:

npm install -D typescript

You can also get editor support by

  • Downloading for Visual Studio 2022/2019
  • Following directions for Visual Studio Code

Here’s a quick list of what’s new in TypeScript 4.9!

  • The satisfies Operator
  • Unlisted Property Narrowing with the in Operator
  • Auto-Accessors in Classes
  • Checks For Equality on NaN
  • File-Watching Now Uses File System Events
  • “Remove Unused Imports” and “Sort Imports” Commands for Editors
  • Go-to-Definition on return Keywords
  • Performance Improvements
  • Correctness Fixes and Breaking Changes

What’s New Since the Beta and RC?

Since the Release Candidate, no changes have been made to TypeScript 4.9.

TypeScript 4.9 beta originally included auto-accessors in classes, along with the performance improvements described below; however, these did not get documented in the 4.9 beta blog post.

Not originally shipped in the 4.9 beta were the new “Remove Unused Imports” and “Sort Imports” commands for editors, and new go-to-definition functionality on return keywords.

The satisfies Operator

TypeScript developers are often faced with a dilemma: they want to ensure that some expression matches some type, but also want to keep the most specific type of that expression for inference purposes.

For example:

// Each property can be a string or an RGB tuple.
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
//  ^^^^ sacrebleu - we've made a typo!

// We want to be able to use array methods on 'red'...
const redComponent =;

// or string methods on 'green'...
const greenNormalized =;

Notice that they’ve written bleu, whereas they probably should have written blue. They could try to catch that bleu typo by using a type annotation on palette, but they’d lose the information about each property.

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ The typo is now correctly detected

// But we now have an undesirable error here - '' "could" be a string.
const redComponent =;

The new satisfies operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression. As an example, you could use satisfies to validate that all the properties of palette are compatible with string | number[]:

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ The typo is now caught!
} satisfies Record<Colors, string | RGB>;

// Both of these methods are still accessible!
const redComponent =;
const greenNormalized =;

satisfies can be used to catch lots of possible errors. For example, they could ensure that an object has all the keys of some type, but no more:

type Colors = "red" | "green" | "blue";

// Ensure that we have exactly the keys from 'Colors'.
const favoriteColors = {
"red": "yes",
"green": false,
"blue": "kinda",
"platypus": false
// ~~~~~~~~~~ error - "platypus" was never listed in 'Colors'.
} satisfies Record<Colors, unknown>;

// All the information about the 'red', 'green', and 'blue' properties are retained.
const g: boolean =;

Maybe they don’t care about if the property names match up somehow, but they do care about the types of each property. In that case, they can also ensure that all of an object’s property values conform to some type.

type RGB = [red: number, green: number, blue: number];

const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0]
// ~~~~~~ error!
} satisfies Record<string, string | RGB>;

// Information about each property is still maintained.
const redComponent =;
const greenNormalized =;

Checks For Equality on NaN

A major gotcha for JavaScript developers is checking against the value NaN using the built-in equality operators.

For some background, NaN is a special numeric value that stands for “Not a Number”. Nothing is ever equal to NaN – even NaN!

console.log(NaN == 0) // false
console.log(NaN === 0) // false

console.log(NaN == NaN) // false
console.log(NaN === NaN) // false

But at least symmetrically everything is always not-equal to NaN.

console.log(NaN != 0) // true
console.log(NaN !== 0) // true

console.log(NaN != NaN) // true
console.log(NaN !== NaN) // true

This technically isn’t a JavaScript-specific problem, since any language that contains IEEE-754 floats has the same behavior; but JavaScript’s primary numeric type is a floating point number, and number parsing in JavaScript can often result in NaN. In turn, checking against NaN ends up being fairly common, and the correct way to do so is to use Number.isNaN – but as we mentioned, lots of people accidentally end up checking with someValue === NaN instead.

TypeScript now errors on direct comparisons against NaN, and will suggest using some variation of Number.isNaN instead.

function validate(someValue: number) {
return someValue !== NaN;
// ~~~~~~~~~~~~~~~~~
// error: This condition will always return 'true'.
// Did you mean '!Number.isNaN(someValue)'?

They believe that this change should strictly help catch beginner errors, similar to how TypeScript currently issues errors on comparisons against object and array literals.

Go-to-Definition on return Keywords

In the editor, when running a go-to-definition on the return keyword, TypeScript will now jump you to the top of the corresponding function. This can be helpful to get a quick sense of which function a return belongs to.

They expect TypeScript will expand this functionality to more keywords such as await and yield or switch, case, and default.