A specialized type of Promise called Deferred

Is there a way to create a Deferred promise that extends Promise while maintaining type-safe usage in scenarios where a typical Promise is expected?

Here's one possible implementation:

export class CustomDeferred<T> extends Promise<T> {                                   
  public _resolveSelf;
  public _rejectSelf;                                                           
  constructor() {
    super(
      (resolve, reject) =>
      {
        this._resolveSelf = resolve;
        this._rejectSelf = reject;
      }
    )
  }                                                                             
  public resolve(val:T) { this._resolveSelf(val); }
  public reject(reason:any) { this._rejectSelf(reason); }                        
}

However, using this implementation may lead to a TypeError: _this is undefined error.

When looking at the Typescript playground example, it becomes apparent that the compiled javascript code has some quirks. In line 15, properties of _this are being assigned even before its declaration.

Answer №1

class Deferred<T> extends Promise<T> {

  private _resolveSelf;
  private _rejectSelf;
  private promise: Promise<T>

  constructor() {
    this.promise = new Promise( (resolve, reject) =>
      {
        this._resolveSelf = resolve
        this._rejectSelf = reject

      }
    )
  }

  public then<TResult1 = T, TResult2 = never>(
    onfulfilled?: ((value: T) =>
      TResult1 | PromiseLike<TResult1>) | undefined | null,
    onrejected?: ((reason: any) =>
      TResult2 | PromiseLike<TResult2>) | undefined | null
    ): Promise<TResult1 | TResult2> {
      return this.promise.then(onfulfilled, onrejected)
    }

  public catch<TResult = never>(
    onrejected?: ((reason: any) =>
      TResult | PromiseLike<TResult>) | undefined | null
    ): Promise<T | TResult> {
      return this.promise.catch(onrejected)
    }

  public resolve(val:T) { this._resolveSelf(val) }
  public reject(reason:any) { this._rejectSelf(reason) }

  [Symbol.toStringTag]: 'Promise'

}

The Deferred class extends the Promise class and provides methods for resolving and rejecting promises. The method signatures of then and catch are inspired by TypeScript's Promise interface and have been cleaned up for readability. Additionally, the [Symbol.toStringTag] line is included to ensure proper compilation in TypeScript.

Answer №2

How can you create a Deferred promise that extends the functionality of a Promise?

It is advised not to do so at all. There are no valid reasons to utilize deferreds.

Furthermore, creating a deferred object that essentially acts as a promise is not recommended. It is best to separate their functionalities:

function defer() {
    var deferred = {};
    deferred.promise = new Promise(resolve => {
        deferred.resolve = resolve;
    });
    return deferred;
}

One may notice something interesting in the compiled javascript code. In line 15, properties of '_this' are being assigned during its declaration.

This behavior is due to how super works: You cannot access this until after the parent constructor has returned and initialized it. However, the promise executor callback gets executed before that point.

To achieve the desired outcome, the following code snippet should be used:

export class Deferred<T> extends Promise<T> {
  public resolve: T=>void;
  public reject: any=>void;
  constructor() {
    var resolveSelf, rejectSelf
    super((resolve, reject) => {
      resolveSelf = resolve
      _rejectSelf = reject
    })
    this.resolve = resolveSelf;
    this.reject = rejectSelf;
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Lambda functions that support multiple languages coexisting in a single directory

As I have lambda functions written in both Typescript and Java, I am contemplating whether to store them all together in a single directory or separate them based on the language. Our infrastructure deployment is done using terraform and CI/CD with Jenki ...

Utilizing Typescript and sinon to mock the functionalities of jsonwebtoken

Looking for help with mocking the function verify in Typescript's jsonwebtoken library. I've installed typescript, jsonwebtoken, sinon, mocha, and chai along with their corresponding types. However, when trying to stub the function, an error occu ...

Display a custom error message containing a string in an Angular error alert

How can I extract a specific string from an error message? I'm trying to retrieve the phrase "Bad Request" from this particular error message "400 - Bad Request URL: put: Message: Http failure response for : 400 Bad Request Details: "Bad Request ...

Can you explain how to incorporate global functions from a javascript library into an Angular 2 project?

Recently I started working with angular-cli and came across a situation where I have an index.html containing a javascript script with some global functions. I want to access these functions in multiple parts of my application. As someone who is new to A ...

Convert an array with three dimensions into a two-dimensional array that includes tuples with two immutable string values

Consider the array below with multiple dimensions: type ParsedLine = [string, string]; type ParsedLines = [ParsedLine, ParsedLine] const myArray: (ParsedLine | ParsedLines)[] = [ ['something', 'somethingElse'], [['foo', & ...

Monitoring and Analyzing Angular2 Events through Google Analytics

After successfully implementing page tracking in Google Analytics with Angular2 using the solution found at , I encountered an issue. I'm trying to integrate the following code snippet within a component: ga('send', { hitType: 'e ...

Searching is disrupted when the page is refreshed in NextJS

When I refresh the page, router.query.title disappears. I have read that I need to use getServerSideProps, but I'm unsure of what to include in the function. Can anyone provide guidance on how to resolve this issue? Update: I followed Yilmaz's s ...

When null is assigned to a type in Typescript, it does not result in an error being triggered

Could someone enlighten me on why this code is not causing an error? import { Injectable } from '@angular/core'; interface Animal{ name: string; } @Injectable() export class AnimalService { lion: Animal = null; constructor() {} get(){ ...

Generate a Jest dummy for testing an IncomingMessage object

I am facing a challenge in writing a unit test for a function that requires an IncomingMessage as one of its parameters. I understand that it is a stream, but I am struggling to create a basic test dummy because the stream causes my tests to timeout. : T ...

There is a method in TypeScript called "Mapping IDs to Object Properties"

I'm currently developing a React app that features several input fields, each with its own unique id: interface IFormInput { name: string; surname: string; address: string; born: Date; etc.. } const [input, setInput] = useState< ...

Listening for Angular 2 router events

How can I detect state changes in Angular 2 router? In Angular 1.x, I used the following event: $rootScope.$on('$stateChangeStart', function(event,toState,toParams,fromState,fromParams, options){ ... }) In Angular 2, using the window.addEv ...

Having trouble receiving accurate intellisense suggestions for MongoDB operations

Implementing communication between a node application and MongoDB without using Mongoose led to the installation of typing for both Node and MongoDB. This resulted in the creation of a typings folder with a reference to index.d.ts in the server.ts file. In ...

Differences between ts-loader and babel-loader when working with TypeScript in webpack

Recently, I set out to compare the compiled output code between these two configurations. ts-loader { test: /\.tsx?$/, use: 'ts-loader', } babel-loader use: { loader: 'babel-loader', options: { p ...

The intricate Q pledge: the assurance of one promise generating a series of other promises

I am facing an http request that is expected to provide a list of tasks, but the process of generating these tasks is quite intricate. Here is a breakdown of how it operates: Retrieve all existing tasks from the database Identify and expire any outdated ...

I continue encountering the Server Error message: "Error: The default export on page "/products/all" is not a React Component."

I have been trying to create a page to display all the products listed in my server.json file (shown below). { "products": [ { "slug": "live-by-the-sun-love-by-the-moon", "title": "Live by the sun, love by the moon.", "price" ...

How do I connect with the global error handling in Vue?

Within my Vue2 application, I am seeking a method to capture global Vue errors and transmit them to a logging or monitoring service such as Sentry. After attempting to overwrite the global error handler of Vue, I noticed that console logs were no longer a ...

The Typescript module in question does not contain any exported components or functions related to

I've encountered an unusual issue while working on a React, Redux TypeScript application. It seems that after making some changes, one of the modules has stopped exporting its members. Here is the folder structure: src |---- components |---- contain ...

associating an enum with a specific key value using generics

Imagine having a basic enum enum MyEnum { a, b, c } Converting the enum into key-value pairs is straightforward: type A<V> = { [k in MyEnum]: V }; const testA: A<string> = { [MyEnum.a]: '', [MyEnum.b]: '', [My ...

I'm looking for a way to modify my standard function so that it can receive warnings

Below is my function called defc export function defc<T extends Record<string,any> >(f:(a:T)=>void){ return function(a:T){ return f(a) } } The purpose of this function is to ensure the correct return type of func ...

Is it possible to use the HostListener in Angular 7 to detect any scroll event occurring on a specific element within a webpage?

I am developing a breadcrumb bar component in Angular 7 that should dynamically hide and show based on user scrolling behavior. To achieve this, I created a directive to track the scroll position of the container element. While my code for capturing the s ...