What's New in Version 5.0 (Const Type, Enums Improvement Speed, Bundler Resolution (r)

Apr 17, 2023
A full rundown of everything that is new in Typescript 5.0

Share on

TypeScript 5.0 was officially released on the 16th of March, 2023, and is now available to everyone for use. The new version introduces a variety of capabilities with the intention to make TypeScript smaller, easier to use, and faster.

In this article this article, you'll explore the new features introduced by TypeScript 5.0 and provide a thorough look at its new options and features.

Getting Started using TypeScript 5.0

Install npm with a -D typescript

The compiler will be installed inside the node_modules directory. It is there that you will be able to use with the the npx tsc command.

Additionally, you can find information on using the newer version of TypeScript in Visual Studio Code in this document.

What's new with TypeScript 5.0?

In this post, we'll examine five significant updates that have been incorporated in TypeScript. These features include:

Modernized Decorators

Decorators have been around in TypeScript for a few years under a flag of experimentation However, the latest version brings them up to speed with the ECMAScript concept that is currently in the stage 3. which means it's at an area where it will be included in TypeScript.

Decorators can be used to customize the behaviour of classes as well as their members in a reusable manner. For example, if there is a class which uses two methods: greet and getAge:

class PersonConst P = a new Person('Ron 30, 30);p.greet() ()p.getAge();

In the real world the class will need complex methods to handle some async logic and produce side effects e.t.c. In this case, it is recommended to add into console.log calls to help debug the methods.

class Person 
 name: string;age: numberconstructor(name is a number, string; age number) 
 this.name = name;
 this.age = age;
 
greet() console.log('LOG Method Execution Commences. ');
 console.log(`Hello My name is $his.name .`);
 console.log('LOG: Method Execution Comes to an End. ');
 
 
 getAge() console.logconsole.log('LOG Method Execution Begins. ');
 console.log(`I am $this.age year old .`);
years oldconsole.log('Method Execution Completes. ');
 

 
 const"p" = "new Person('Ron', 30);p.greet() //p.getAge ();

This is a frequently occurring pattern and it's a good idea to have a solution to be applied to all methods.

The decorators step in. We can define a function named debugMethod which appears like this:

function debugMethod(originalMethod: any, context: any) replaceMethod returned;

In the above code, the debugMethod is the first method to be used ( originalMethod) and returns a function that accomplishes:

  1. It logs an error message "Method Execution begins.".
  2. It passes the method of origin as well as all of its Arguments (including the argument for this).
  3. It logs a message "Method Execution Ends.".
  4. Returns whatever the original method yielded.

By using decorators, you can apply to your methods the method of debug to your methods such as in the code in the following:

class Personconst p = a new Person('Ron 30, 30) --p.greet() ()p.getAge();

This will output this:

Log: Entering the method. Hello, my name is Ron. Log: Exiting method. LOG: Entering method. I'm 30 years old. LOG: Exiting method.

When defining the decorator method ( debugMethod) it is necessary to define a second parameter provided, this one is as "context" (it's the object that defines the context which contains information about how the decorator method is declared along with what the methods name is). You are able to modify the parameters of your method's debugMethod to obtain the name of the method from the context object:

function debugMethod(
 originalMethod: any,
 context: ClassMethodDecoratorContext
 ) 
 const methodName = String(context.name);
 function replacementMethod(this: any, ...args: any[]) 
 console.log(`'$methodName' Execution Starts.`);
 const result = originalMethod.call(this, ...args);
 console.log(`'$methodName' Execution Ends.`);
 return result;
 
 return replacementMethod;
 

After you have run your code and output is generated, it will be able to identify each method, which is decorated using the debugMethod decorator:

"greet" Execution begins. My name is Ron. "greet" Execution Ended. 'getAge' Execution Starts. I'm 30. "getAge" Execution Stops.

There is more to what you can do with decorators. You can refer to the Original pull request for more information on how to use decorators in TypeScript.

Introduce Const Type Parameters

This is another big release that gives you a new program that uses generics to enhance the accuracy of inferences you make whenever you invoke functions. When you define values using const, TypeScript infers the nature of the type, not the literal values.

/Inferred type: string[]name of const = ['John' "Jake" and "Jack'

To get the intended inference it was necessary to make use of the const assertion by adding "as const":

// Inferred type: readonly ["John", "Jake", "Jack"]
 const names = ['John' "Jake' and "Jack'in const

When you use functions, it's similar. The code below shows the inferred form of countries is a string[]:

type HasCountries =  countries: readonly string[] ;
 function getCountriesExactly(arg: T): T['countries'] 
 return arg.countries;
 
 
 // Inferred type: string[]
 const countries = getCountriesExactly( countries: ['USA', 'Canada', 'India'] );

There is a possibility that you would like to have a specific kind of which one method to address this issue has been to add to the as const assertion:

/Inferred type: read-only ["USA", "Canada", "India"]
 const names = getNamesExactly(Countries: ['USA'], 'Canada', "India']);

This isn't easy to keep track of and then implement. But it is now possible to do this with TypeScript 5.0 includes a brand new feature which allows the addition of a const modifier to the declaration of a type parameter, which will automatically apply const-like inferences as standard.

kind HasCountries countries read-only string[] Function getNamesExactly(arg: T) T['countries'['countries'] 
 return arg.countries;
 
* Inferred type read-only ["USA", "Canada", "India"]
 const names = getNamesExactly("'USA', "Canada', "India'");

Utilizing const type parameters allows programmers to communicate their intent in a more clear manner when writing code. If a variable is designed to be permanent and not be changed, using a const type parameter ensures that it can never be accidentally altered.

Check out the initial pull request to find out more details about how the const type parameter functions in TypeScript.

Improved Enums

Enums in TypeScript are a powerful tool which allows developers to create an array of named constants. In the version 5.0 of TypeScript 5.0 the enums are improved. made to enums to make them even versatile and beneficial.

For example, if you've got this enum that you have passed to the function:

enum Color 
 Red,
 Green,
 Blue,
 
 
 function getColorName(colorLevel: Color) 
 return colorLevel;
 
 
 console.log(getColorName(1));

Prior to the introduction of TypeScript 5.0 it was possible to pass an error-prone level number and it would not throw any error. With the introduction of TypeScript 5.0 the program will instantly throw an error.

Also, the new release converts all enums to union enums through the creation of an individual type for each member computed. This enhancement allows for the narrowing of all enums as well as the reference of their types to the members:

enum Color 
 Red,
 Purple,
 Orange,
 Green,
 Blue,
 Black,
 White,
 
 
 type PrimaryColor = Color.Red | Color.Green | Color.Blue;
 
 function isPrimaryColor(c: Color): c is PrimaryColor  c === Color.Green 
 
 console.log(isPrimaryColor(Color.White)); // Outputs: false
 console.log(isPrimaryColor(Color.Red)); // Outputs: true

Performance Improvements with TypeScript 5.0

TypeScript 5.0 contains a variety of major changes in the structure of code as well as data structures and algorithmic extensions. It has improved the whole TypeScript experience, from the installation phase to its execution, making it more effective and faster.

The difference, for instance, between the sizes of packages in TypeScript 5.0 and 4.9 is quite impressive.

TypeScript was moved recently from namespaces to modules permitting it to utilize new build tools to perform optimizations like scope hoisting. Additionally, the removal of some obsolete codes has removed about 26.4 MB from TypeScript 4.9's 63.8 MB package size.

TypeScript package size
TypeScript package size

Here are some other interesting results in speed and size between TypeScript 5.0 in comparison to 4.9:

Scenario The Time or Size Relative to TS 4.9
Material-Ui construction time 90%
TypeScript Compiler startup time 89%
Build time for Playwright 88%
TypeScript Compiler self-build time 87%
Outlook Web construction time 82%
VS Code build time 80%
Typescript NPM Package Size 59%

Bundler Resolution for Better Module Resolution

When you write an import statement in TypeScript the compiler must to know what import is referring to. It does this with the help of the resolution module. As an example, if you write import a to "moduleA", the compiler has to be aware of the meaning of a in moduleA to check its use.

In TypeScript 4.7 Two new options were introduced for the --module as well as moduleResolution options: node16 and nodenext.

As an example, for the ECMAScript module in Node.js, any relative import requires a file extension for it to work correctly:

import * as utils from "./utils"; // Wrong import * as utils coming from "./utils.mjs" • The correct way to do it

TypeScript introduces a new approach called "moduleResolution bundler." The strategy could be implemented using this code into"compilerOptions" or the "compilerOptions" section of the TypeScript configuration file:


 "compilerOptions": 
 "target": "esnext",
 "moduleResolution": "bundler"
 
 

This new strategy is suitable for those using modern bundlers including Vite, esbuild, SWC, Webpack, Parcel, as well as others that use a hybrid lookup strategy.

You can check the initial pull request as well as its implementation to learn more about how module Resolution bundler functions in TypeScript.

Deprecations

  1. Runtime Requirements: TypeScript now targets ECMAScript 2018. The package specifies a minimum engine expectation of 12.20. Therefore, users of Node.js need to have a version 12.20 or greater to utilize TypeScript 5.0.
  2. lib.d.ts Modifications: There have been modifications to the ways that kinds for the DOM are created, and this could affect code that is already in use. In particular, certain properties were converted into numeric literal types. Also, the properties and methods for cut or copy and paste handling are being transferred across interfaces.
  3. API breaking changes: Some unnecessary interfaces have been removed, and some improvements in correctness were added. TypeScript 5.0 is also being ported into modules.

TypeScript 5.0 has deprecated certain settings and their corresponding values, including target: ES3, out, noImplicitUseStrict, keyofStringsOnly, suppressExcessPropertyErrors, suppressImplicitAnyIndexErrors, noStrictGenericChecks, charset, importsNotUsedAsValues, and preserveValueImports, as well as prepend in project references.

These configurations will stay applicable until TypeScript 5.5, a warning is issued to warn users who have not yet used these configurations.

Summary

In this article we have covered several of the most important new features and enhancements that TypeScript 5.0 brings, such as enhancements to enums, the resolution of bundlers, as well as const types, as well as increases in speeds and sizes.

It's your turn! Which features or enhancements are you most impressed with in TypeScript 5.0? Do you have any notable ones that we haven't considered? Please let us know via the comment section below.

  • Easy setup and management in the My dashboard
  • Support is available 24/7.
  • The top Google Cloud Platform hardware and network, that is powered by Kubernetes to ensure maximum capacity
  • An enterprise-level Cloudflare integration to speed up as well as security
  • Reaching a global audience with up to 35 data centers, and 275 PoPs worldwide