April 6, 2023

TypeScript - Promise.all()

The Promise.all() method is one of the promise concurrency methods. It takes an interable of promises as input and returns a single promise object. It is useful for aggregating the result of multiple promises passed as input.

  • This returned promise fulfills when all of the input's promises fulfill/resolve.
  • It rejects immediately when any of the input's promises rejects.

It is typically used when there are multiple asynchronous tasks that we want to fulfill before the code execution continues.

In this example, since all the input promises are resolved, so the final promise will also get resolved.

const p1 = 10;
const p2 = Promise.resolve(20);
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
	resolve("value from promise3");
  }, 100);
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values);
});

Output will be :

[ 10, 20, 'value from promise3' ]

Note that, the values parameter in .then() function will be an array containing all the output values from each input promise.

Lets see an example, if one of the promise from input is rejected.

// pass 4 promises: (1,2,3 and rejected-promise)
const p = Promise.all([1, 2, 3, Promise.reject(new Error("some error"))]);

p.then((values) => {
  //this will not get called.
  console.log(values);
})
.catch((error) => {
  //catch here for rejected promise
  console.error(error.message);
});

Output will be :

some error

Promise.all() executes the success callback when all the input promises are resolved. If any of the promise is rejected, then the rejection callback will be executed.

References:

Related Post(s):

March 20, 2023

JavaScript - What is Promise

A promise object is an instance of the Promise class. It represents the eventual completion or failure of an asynchronous operation.

A Promise is kind of proxy for a value might be unknown when the promise is created. You can associate handlers with a promise to receive notification/result of success and failure of asynchronous operation performed by promise executor.

Promise executor is simply a function passed to the constructor of Promise class, it controls the behavior of promise's resolution (success )or rejection (failure).

Promise lets asynchronous methods return values like synchronous methods. Instead of immediately returning the final value, it returns a promise object as a mechanism to supply the value at some point in the future.

A Promise object can have one of these states:

  • pending: initial state (neither fulfilled nor rejected)
  • fulfilled: when the operation was completed successfully.
  • rejected: when the operation failed.

To create a promise, we use new Promise(executor) syntax and provide an executor function as an argument.

To consume a promise, we use .then() function to receive the result of promise.

The .then() method of the promise object takes up to two arguments:

  1. First argument is a callback function for the fulfilled case of the promise (usullay known as resolve)
  2. Second argument is a callback function for the rejected case (usullay known as reject).

An example:

let myPromise = new Promise(function(resolve, reject) {
    let status_code = 200;  //to call resolve/success
    //let status_code = 201; //to call reject/failure
  
    if (status_code == 200) {
      resolve("Status code is 200");
    } else {
      reject("Status code is not 200");
    }
  });
  
myPromise.then(
	function(value) {console.log("Success:", value);},
	function(error) {console.log("Error:", error);}
);

For this example, inside the Promise executor function, if the variable status_code value is 200 then it will call resolve handler of the promise, which ultimately fall in the fulfilled callback of .then() function.

If you change the status_code value to anything other than 200, then it will call reject handler of the promise, which ultimately fall in the rejected callback of .then() function.

References:

Related Post(s):

TypeScript - Promise only refers to a type, but is being used as a value

When using Promise in TypeScript code and transpiling, it generates the error:

'Promise' only refers to a type, but is being used as a value here. 
Do you need to change your target library? 
Try changing the 'lib' compiler option to es2015 or later

There could be following reasons/fixes for this issue:

  • Check in tsconfig.json file, if the target property (under compilerOptions) is set to es2015 or later (as suggested in the error message).
    {
        "compilerOptions": {
            "target": "es2015",
        }
    }
    
  • In tsconfig.json file, add lib property (under compilerOptions), and set it values to es2015 or later.
    {
        "compilerOptions": {
            "target": "es2015",
            "lib": ["dom", "es2015", "es5", "es6"],
        }
    }
    
  • A quick work around for this error is just removing the type check for Promise, rather than fixing it. Declar the Promise as a variable with type any.
    declare var Promise: any;
    
  • Try to install @types/node from npm;
    npm instal @types/node
    
  • Please be aware that if you are running the tsc command with a file name, then the compiler will ignore the tsconfig.json file. For example, transpiling the file like this:
    tsc myfile.ts
    
    You can edit the tsconfig.json to include a set of files with files property, e.g:
    {
        "compilerOptions": {
            "module": "commonjs",
            "noImplicitAny": true,
            "removeComments": true,
            "preserveConstEnums": true,
            "sourceMap": true,
            "target": "es2015",
            "lib": ["dom", "es2015", "es5", "es6"],
        },
        "files": [
            "myfile.ts",
            "service1.ts",
            "common.ts",
            "util.ts",
        ]
    }
    

February 23, 2023

TypeScript - Class Decorators

The class decorator takes the constructor function as a parameter, allows us to change the way how this class is initialized.

Let's say we have a couple of classes Customer and Order. It is required that every class needs to have created property.

The normal solution is to create a base class which will have common fields and allow the childern to inherit from this.

In this example, we will use decorator to achieve this behavior, the decorator function will receive the target's constructor function as a parameter, and add the created property to its prototype.

Here is the code for decorator:

function EntityWithTimeStamp(constructorFunction: Function) {
    constructorFunction.prototype.created = new Date().toLocaleString("en-US");
    console.log("decorator called");
}

It receives constructorFunction(of the target class) as parameter, and adds created property to its prototype.

The decorator is ready to be used in each entity. We only need to add @EntityWithTimeStamp before class definition.

Here we define our classes and adds @EntityWithTimeStamp decorator.

@EntityWithTimeStamp
class Customer {
  constructor(public name: string) {
    console.log("Customer controctor called");
  }
}

@EntityWithTimeStamp
class Order {
  constructor(public amount: number) {
    console.log("Order  controctor called");
  }
}

Both of these classes have defined their own public properties received in constructor. Also they will have an additional property created which will be added by the decorator.

You can create objects of these classes as usual, and output the public properties to console:

let customer = new Customer("Idrees");
let order  = new Order(100);

console.log(order.amount);
console.log(customer.name);

Note that the decorator does not change the TypeScript type and the new property created is not known to the type system. The following lines will give you the error because compiler will not find created property in these referenced classes/types:

console.log(order.created);
console.log(customer.created);

Error message:

error TS2339: Property 'created' does not exist on type 'Customer'.
error TS2339: Property 'created' does not exist on type 'Order'.

There is a work around this issue, you can access the created property by temporarily casting the object to type any.

console.log((<any>order).created);
console.log((<any>customer).created);

Output will display the value of crearted property, which shows that decorator has added this field as the class member.

Related Post(s):

February 22, 2023

Decorators in TypeScript

Decorators provide a mechanism to metaprogramming syntax in TypeScript, which is a programming technique basically means "writing code that writes code".

Decorators allow us to decorate members of a class, or a class itself, with extended functionality. This is a function that we can hook into our code, to extend with some behavior and helps us to write code abstractions and provide extension mechanism.

When you apply a decorator to a class or a class member, it will actually call a function that is going to receive details of target (what is being decorated), and the decorator implementation will then be able to transform the code dynamically (e.g. adding extra functionality, and reducing boilerplate code).

The decorators are used on class itself and its members:

  • class definition
  • properties
  • methods
  • accessors
  • parameters

Note that:

Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript.

Before using decorators in TypeScript, we need to enable it. If the decorator support is not enabled and you try to compile a TypeScript file/project that is using decorator, it will give you this error:

 error TS1219: Experimental support for decorators is a feature that is subject to change 
 in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig'
 to remove this warning.

We have two ways to enable decorators support in TypeScript:

  • You can enable decorators support at compile time. When using the TypeScript Compiler CLI (tsc), we need to provide additional flag --experimentalDecorators:
    tsc --experimentalDecorators
    
  • When working in a project that has a tsconfig.json file, to enable decorators support you can add the experimentalDecorators property (with value true) to the compilerOptions object:
    {
      "compilerOptions": {
        "experimentalDecorators": true
      }
    }
    

Related Post(s):