What is the best way to combine async/await with a custom Promise class implementation?

I've created a unique Promise class. How can I incorporate it with async/await?

type Resolve<T> = (x: T | PromiseLike<T>) => void
type Reject     = (reason?: any) => void

class CustomizedPromise<T> extends Promise<T> {
    constructor(f: (res: Resolve<T>, rej: Reject) => void) {
        super((resolve, reject) => f(
            (x) => {console.log(`I resolved to ${x}!`); resolve(x)}, 
            reject
        ))
    }
}

function increment(x: number): CustomizedPromise<number> {
    return new CustomizedPromise(resolve => resolve(x + 1))
}

I can easily await my customized promise:

function logResult() {
    const result = await increment(2)
    console.log(`I received result ${result}`)
}

>> logResult()
// I resolved to 3!
// I received result 3!

However, returning my customized promise from an async method is problematic:

async toggle(): CustomizedPromise<number> {
    const result = await increment(2)
    return CustomizedPromise.resolve(result * 5)
}
// ERROR: The return type of an async function or method must be the global Promise<T> type. 
// Did you mean to write 'Promise<number>'?

If I suppress this error using ts-ignore, it functions properly*:

// @ts-ignore <-- Is there a workaround for this?
async function toggle(x: number): CustomizedPromise<number> {
    const result = await increment(x)
    return CustomizedPromise.resolve(result * 5)
}

async function main() {
    const result = await toggle(2)
    console.log(`I received result ${result}!`)
}

>> main()
// I resolved to 3!
// I resolved to 15!
// I received result 15!

Check out this Typescript playground example.

(*Although, there are some occurrences of undefined promises being spawned, they don't appear to impact the overall outcome.)

Is there a way to persuade Typescript to allow me to utilize the async keyword on a method that returns my custom promise?

Answer №1

Is it possible to implement async/await with a custom Promise subclass?

Unfortunately, it is not possible. You can use await on any object that has a .then() method, including instances of your promise subclass. However, an async function will always return a built-in Promise, not an instance of your subclass.

Can TypeScript be persuaded to allow the async keyword on a method that returns a custom promise?

No, TypeScript does not support methods returning custom promises. This limitation is enforced by the JavaScript runtime and cannot be circumvented using TypeScript.

[Despite encountering an error], the code seems to work fine

In reality, it does not work properly, as shown in the following example:

async torgle(): Promise<number> {
//              ^^^^^^^^^^^^^^^
    const answer = await inc(2)
    return LoggingPromise.resolve(answer * 5)
}

It is important to remember that async/await syntax translates to traditional promise chaining under the hood:

torgle(): Promise<number> {
    return new Promise((resolve, reject) => {
        Promise.resolve(inc(2)).then(answer => {
            resolve(LoggingPromise.resolve(answer * 5));
        });
    });
}

Even if you call LoggingPromise.resolve() within the method, the returned value remains a native promise:

const promise = torgle();
console.log(promise instanceof LoggingPromise); // false

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

Is there a way to decrease these values in my firestore using a loop?

My goal was to decrease the quantities of the color upon form submission. The setup includes forms where users can select a product, enter quantity, choose colors, and add more products. Upon submitting the data, it looks like this: The Firestore documen ...

When the user clicks on the iframe, they will be redirected to the

My goal is to create a scenario where clicking on an iframe opens the same URL in a new browser tab, while ensuring that scroll and other mouse events within the iframe are not affected. I have experimented with various approaches but none have been succe ...

Show a table when a button is clicked using Javascript

Undertaking a project called: Tennis Club Management involving javascript, HTML, CSS, and bootstrap. The project includes a Login Page (index.html) and a Manage Players Page (managePlayers.html). Within the managePlayers.html, there are two buttons - Add P ...

Why is the value of the select element in AngularJS an object?

Here is a JSON object: { "9000A": { "LOCname":"A Place", "LOCid":"9000A" }, "2700C": { "LOCname":"C Place", "LOCid":"2700C" }, "7600B": { "LOCname":"B Place", "LOCid":"7600B" } } To ...

Confirming the validity of an email address with Md-chips

Email Validation for MD-Chips Struggling with creating an email validation for md-chips. The current expression I'm using is not working as expected, since the ng-keypress directive is triggered every time I type something. Any suggestions on how to ...

Implementing an event handler within a functional component using hooks in React

I'm currently exploring functional components and hooks. I have a component that retrieves an array of quotes from an API and is supposed to randomly select one to pass as a prop to a child component named "Quote". import React, {useState, useEffect} ...

What is the best way to enable external events for Fullcalendar in an Angular environment?

Struggling to integrate external events with Fullcalendar and Angular. Admittedly, I am new to Angular and there are aspects that still elude me. Fullcalendar provides a guide on setting up with Angular, available here. Initially, I managed to set up the ...

During development, getStaticPaths and getStaticProps successfully function, however, the prop during build time becomes undefined

I am currently working on developing an eCommerce platform utilizing Next.js. One of the challenges I encountered was in the product page where dynamic routes are used. Specifically, I implemented getStaticProps to fetch the product and getStaticPaths to g ...

When using child_process to run a Python script in Node.js, a promise may not resolve properly if the process exits before all

Currently, I am facing an issue while trying to execute sublist3r within a node app. The script runs successfully but only displays the banner before abruptly exiting after about 5 seconds. Typically, the script should interact with the web and take approx ...

Retrieve the content from a textarea and insert it into a different textarea with additional text included

Users can input HTML codes into a textarea named txtar1. A 'generate' button is available; Upon clicking the 'generate' button, the content of txtar1 will be transfered to another textarea named txtar2 with additional CSS code. Here&ap ...

Why is my Angular 2 service not showing up in my application?

Trying to access a JSON file using an Angular service has been unsuccessful. While I can easily read and bind the JSON data without the service, attempting to do so with the service results in an error message: Failed to load resource: the server responde ...

React Native app experiences a start-up crash caused by SoLoader problem

I'm encountering a problem with my Android app (iOS is working fine). Every time I build it, the application closes before launching. I've tried various solutions found on Github and here, but haven't been able to resolve it yet. The instal ...

Classbased Typescript implementation for managing state with a Vuex store

Hey everyone, I'm currently working on a Vue project with Vuex using decorators for strong typing in my template. As someone new to the concept of stores, I am struggling to understand how to properly configure my store to work as expected in my comp ...

A function designed to detect errors based on the parameters supplied as arguments

In order to ensure secure access to my restful API, I am looking to implement an authentication function called "access". I would like the function to have the following structure whenever a user interacts with the server: access(id , token ,function(err) ...

When navigating back, the Bootstrap Multistep Form breaks down

Tools I'm currently utilizing: HTML, CSS, Javascript, Bootstrap 3 Library / Package in use: https://codepen.io/designify-me/pen/qrJWpG Hello there! I am attempting to customize a Codepen-based Bootstrap Multistep Form from the provided link abov ...

One potential solution is sending a message to a user via a server using JavaScript on Node.js

Hey there, I've encountered a minor issue and would appreciate your help. Recently, I developed a weather program in NodeJs where users can search for the weather in their city. However, I'm facing a challenge with displaying the weather data to ...

Passing data as a parameter from the view to the controller using AngularJS

I am attempting to retrieve data from a view, which must be passed as a parameter in a function in order to populate an array in the controller. However, I am not receiving any objects in return. Here is what I have tried: VIEW <div ng-repeat="cssfram ...

The API response appears to be a successful 200 status code, however the actual result is a

I'm currently working with a VUEJS / VUEJS Resources code snippet that retrieves data from an API service. fetchData: function(name){ var self = this; self.$http.get('http://www.apiservice.com/', { params: { ...

What exactly is HTML cloud storage all about?

As I work on developing an app through phonegap, one question that comes to mind is the possibility of storing information online. For instance, if there's a number variable that increases when a button is pressed, can this value be saved somewhere an ...

When integrating react-hook-form with Material-UI TextField in a form, an error occurs stating that "TypeError: e.target is undefined" when

Hey there, I stumbled upon something fascinating and could really use some assistance. Every time I attempt to perform an onChange, I run into the following error: TypeError: e.target is undefined. Here's a snippet of my setup: import React, { useE ...