09 Aug 2024
4 min

The most important new features introduced by TypeScript 5.5

Like many things, Typescript still expands to provide the best possible solution and to make the development process smoother. Let’s review what has been changed and how we can use it in our daily development process.

Support for new set methods.

Since the recent version of TypeScript, the new set methods like union() or difference() are fully supported. If you want to read more about these new methods, click here. To keep this article cohesive, we are not going to talk about every new method, however,  we can sum up a few of them. Take a look at this case:

const garage = new Set(["Volkswagen", "Moto bike"]);
const orders = new Set(["Lawn Mower", "Bike"]);


const sumUp = garage.union(orders);// {'Volkswagen','Moto bike', 'Lawn Mower', 'Bike'}

As we can see, we have two different Sets (garage and orders). To const sumUp we assigned the result of the union method which was invoked on the instance of the garage Set. The result is okay, but there is a problem with TypeScript if you are using the version lower than 5.5:

Property 'union' does not exist on type 'Set<string>'.(2339)

To avoid this error, we could obviously treat garage Set as any:

const garage = new Set(["Volkswagen", "Moto bike"]) as any;

But as we know, we should avoid using any type if possible. Instead of using any type, we should consider updating TypeScript to the newest version. The same happens if we use another new set method, for example difference method.

Improved Type Predicates

This improvement can definitely change the way we develop our code, especially when we work with arrays. Let’s consider the the following case:

const grades = [3, 4, "A", "C", 2, 5];

As we can see, there is an array that consists of grades, which can be a number or a string. Let’s assume that we want to filter that array by its type.

const numbericGrades = grades.filter((grade) => {
   return typeof grade === 'number'
}) // [3, 4, 2, 5] 

Until now, everything looks great, but if we had tried to iterate through the numericGrades array to get an average grade, we would have seen a TypeScript error.

let averageGrade = 0
for(let i = 0; i++; i < numbericGrades.length) {
   const singleGrade = numbericGrades[i];
    averageGrade = averageGrade + singleGrade / numbericGrades.length;
}

Error displayed:

The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.(2362)
const singleGrade: string | number

We can avoid this TS error in a few ways. In the old way, we can treat singleGrade as a number:

const singleGrade = numbericGrades[i] as number;

Obviously, we could use a constructor of number to coerce a variable to be of a number type (it’s not a best practice, you should consider avoiding it)

const singleGrade = Number(numbericGrades[i]);

The recent version of TypeScript no longer needs this. You can organize your code as shown in the for loop. TypeScript can handle this type of situation.

Influence On Another Libs

As an extension of the previous section, we should know that we can take advantage of improved type predicates not only in pure TS files but also, for example, in files that use RxJS lib. The main subject of this article is not that lib, but to show you how we can use this, let’s consider the following case.

class Example {
  private _myArr = of("11", 1);
}

As we can we it is an observable created by using of operator. Similarly to the previous case, we want to filter by the value type.

this._myArr.
  pipe(
    filter((el) => {
      return typeof el !== 'string'
    }),
    tap((filteredElement) => 
      console.log(filteredElement * 10)
    )
  ).subscribe()

In the previous version of TypeScript this error would be shown:

The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.(2362)

Syntax Checking On Regular Expressions.

With the new version of Typescript, regular expressions and their syntax are no longer skipped. From now on TypeScript handles with them and performs basic syntax checks. This is a huge improvement but you have to be watchful. The syntax checks are performed only for regular expression literals. It does not work with the RegExp object constructor as it is described below:

const regPattern = /angular18(/ //error:  ')' expected.
const regExp =  RegExp(" /angular18(/") //no error thrown


//Typescript Version Lower than 5.5:
const regPattern = /angular18(/ /no error thrown

Improved Form Narrowing 

The next big step in the process of improving TypeScript is easier access to object properties, which is provided by better type narrowing. Let’s consider the following case:

type ObjectType = Record<number, number | string>;


const someObject: ObjectType = {
   10: 30
}


function downCase(obj: ObjectType, key: number) {
   if (typeof obj[key] === "number") {
       return {
           key: obj[key] * 10
       }
   } else {
       return {
           key: 'Key is not a number'
       }
   }
}

We have created a function that checks if the object’s property type is a number, and if so,  it returns an object with multiplied property. In any other case, it returns an object with a  hardcoded property value. Developer were able to see the following error until now:

The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.(2362)

This error does not occur in the recent update of TypeScript. What is more, we don’t need any workaround like that:

const value = Number(obj[key])
    return {
        key: value * 10
    }

Improved Type Imports in JSDoc

The latest version of Typescript supports a new @Import comment tag. This feature has been introduced to restrain the problems with imported types, as they do not exist during the runtime of our application. Let’s see below:

/** @import { ObjType } from "types" */


/**
* @param { ObjType } objExample
*/


function myFunc(objExample) {
   // ...
}

Before the recent release, developers had to consider making workarounds like this:

/**
* @param {import("Types").ObjType} objExample
*/

As we can see, there is no need for that quite ugly workaround.

Package Size

Last but not least, the package size has been reduced due to rebuilding tsserver.js and typingInstaller.js files. These files are now part of the public API and they do not produce a standalone bundle.

Before After Difference(%)
Packed 5.51 MiB 3.76 MiB 31.66%
Unpacked 30.18 MiB 20.36 MiB 32.55%

What about Angular?

If you are an Angular Developer and you really want to take advantage of new TypeScript features, you should update your Angular version to 18.1. Since this version, the new features are supported. You can read more about new changes introduced in Angular here

Summary

As described, the latest TypeScript version introduces many changes. It is worth mentioning that with each new iteration, TypeScript becomes a better tool for our daily work. It is too early to talk about the next iteration, but we hope that it will be as fruitful as the recent one.

Thank you for reading my article.

Share this post

Sign up for our newsletter

Stay up-to-date with the trends and be a part of a thriving community.