Encountering TypeScript error TS2345 while attempting to reject a Promise with an error

I recently encountered a perplexing TypeScript error message that I am struggling to comprehend. The specific error reads as follows:

error TS2345: Argument of type '(error: Error) => void | Promise' is not assignable to parameter of type '(reason: any) => IdentityKeyPair | PromiseLike'. Type 'void | Promise' is not assignable to type 'IdentityKeyPair | PromiseLike'.

Initially, my code was functioning without issues until TypeScript raised an objection after I made the following modification:

.catch((error) => {
  if (error instanceof RecordNotFoundError) {
    let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
    return this.store.save_identity(identity);
  } else {
    return reject(error);
  }
})

This snippet was part of a larger block of code which previously worked flawlessly:

public init(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
      .catch((error) => {
        let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
        return this.store.save_identity(identity);
      })
      .then((identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
      })
      .then((lastResortPreKey: Proteus.keys.PreKey) => {
        return resolve(lastResortPreKey);
      })
      .catch(reject);
  });
}

However, after implementing the updated code provided earlier, the compiler flagged an issue with the line return reject(error);, triggering error code TS2345.

Screenshot:

https://i.sstatic.net/hnsav.png

This predicament has arisen while utilizing TypeScript version 2.1.4.

Answer №1

Experiment with the code below. When you find yourself in a then or catch block, you have the option to return a Promise or a value that will be automatically wrapped into a Promise. By manually handling Promises, you can simply call the resolve and reject functions without the need to explicitly return anything. If you were to do something like reject(error), it would attempt to turn that into a Promise and pass it to the next then block, causing the error you encountered. To clarify, returning a value within a handler signifies that the chain of operations should continue with this new value. In your scenario, rather than continuing the chain, you likely want the Promise you are creating to resolve or reject based on specific conditions.

public initializePromise(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.storage.loadIdentity()
      .catch((error) => {
        if (error instanceof RecordNotFoundError) {
          let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.create();
          return this.storage.saveIdentity(identity);
        } else {
          throw error;
        }
      })
      .then((identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        return this.storage.loadPrekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
      })
      .then((ultimatePreKey: Proteus.keys.PreKey) => {
        resolve(ultimatePreKey);
      })
      .catch((error) => {
        reject(error);
      });
  });
}

Answer №2

If you encounter a Promise chain, there is no way to halt it completely (except for cancellation). Even using reject() within the chain is not the correct approach as it involves wrapping a Promise in another constructor, which is misuse of Promises.

Instead of trying to stop the chain entirely, consider allowing the rejection to propagate down the chain by rethrowing it when necessary. Eventually, after all the .catch() handlers have been exhausted, the Promise returned from your function will reject.

When thinking about handling this in synchronous code, you would typically use something like:

try {
  try {
    actionThatThrows();
  } catch (err) {
    breakEverything();
  }
  continue other steps
} catch(err) {
  generalErrorHandling();
}

However, this approach is not suitable for Promises. Instead, it's recommended to separate distinct actions into functions that can resolve or reject independently and utilize Errors as intended - as exceptions that bubble up the stack until they find a handler.

Additionally, if you are working with long asynchronous flows and using TypeScript 2.1.x, consider implementing an async function for better management of your code.

Answer №3

Your response is redundant there; it marks the conclusion of the onRejection callback. Furthermore, employing return reject() will still execute the subsequent .then() promise as expected. Nevertheless, by throwing the error instead, it will be passed down to the subsequent promises until reaching the .catch(reject);

To summarize: within any catch/then block, returning a value will resolve the child promise, while throwing an error will reject it.

I have revised your code to ensure a smoother flow of the promise chain.

public initialize(): Promise<Array<Proteus.keys.PreKey>> {
  return new Promise((resolve, reject) => {
    this.store.load_identity()
    .catch(
      (error) => {
        if (error instanceof RecordNotFoundError) {
          let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
          return this.store.save_identity(identity);
        } else {
          throw error;
        }
      }
    )
    .then(
      (identity: Proteus.keys.IdentityKeyPair) => {
        this.identity = identity;
        resolve(this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID));
      },
      reject
    )
  });
}

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 it possible to insert an image directly into the <img> tag without having to first send it to the server?

I've created an upload form that allows users to submit images: <form> <input accept="image/jpeg, image/gif, image/png" type="file" name="image" id="image" class="UploadInput" onchange="submitImageUploaderForm()"/> </form> Once t ...

Executing a command efficiently in Javascript with the get method

The command that needs to be sent to the embedded device is in the form of a GET method. However, the value continuouspantiltmove: String(pt) is not being properly transmitted to the CGI script through Google Chrome, causing it to fail. Since I do not hav ...

Error in electron-builder: Module 'dmg-license' was not found

Seeking a straightforward method to create an electron app for macOS from a Linux machine. Unfortunately, the electron-builder -m command is not functioning properly. Here is the complete output of the command: electron-builder -m • elec ...

Customize your click event with conditional styling in React

When the onClick event is triggered, I am attempting to modify a class by calling my function. It appears that the function is successfully executed, however, the class does not update in the render output. Below is the code snippet: import React from &ap ...

An Angular module downloaded from npm seems to be lacking the required @NgModule declaration

There seems to be a missing @NgModule and @Directive declarations in an NPM module, even though they exist in the source code on Github. This is causing an issue with importing a directive for databinding from an HTML attribute. I am attempting to utilize ...

Python, JavaScript, and Selenium RC all work together within loop statements on .aspx pages

I've been diving into Python on my own for the past few months. My initial project involves creating a browser driver test case with the Selenium RC web driving framework (I'm avoiding importing webdriver to keep things simple). The goal is to ha ...

Utilizing Typescript for Efficient Autocomplete in React with Google's API

Struggling to align the types between a Google address autocomplete and a React-Bootstrap form, specifically for the ref. class ProfileForm extends React.Component<PropsFromRedux, ProfileFormState> { private myRef = React.createRef<FormContro ...

Merge text inputs to preview content prior to form submission

I've been on the hunt for a solution to display the collective values entered into multiple text box fields as they are being typed. Currently, I have 6 text boxes (description1, description2, description3, description4, description5, description6) wh ...

Attributes for 'v-bind' directives must have a value specified

Struggling to implement a tree structure in vue.js and encountering an issue with element props. Any assistance would be greatly appreciated. I've attempted using :content="{{tempCont}}" as well as content="{{tempCont}}", but neither approach proved ...

Exploring table iteration in Angular 7

I am looking to create a table with one property per cell, but I want each row to contain 4 cells before moving on to the next row... This is what I want: <table> <tr> <td> <mat-checkbox>1</mat-checkbox& ...

Express server encounters a 404 error while processing a POST request

Recently, I encountered an issue while trying to post data to my express server using a function that is triggered by clicking a button. Here's the code snippet of the function: const fetchData = async () => { const response = await fetch(&apos ...

Transferring information from MySQL to Vue.js data attribute

I have retrieved some data from MySQL and I am looking to integrate it into a vue.js data property for seamless iteration using v-for. What is the ideal format to use (JSON or array) and how can I ensure that the data is properly accessible in vue.js? &l ...

Exploring the implementation of if statements within the array map function in the context of Next.js

Is there a way to wrap certain code based on the remainder of the index number being 0? I attempted the following approaches but encountered syntax errors. {index % 3 === 0 ? ... : ...} {index % 3 === 0 && ...} export default function UserPosts() { / ...

Determining in Angular 8 whether a value has been altered by a user or by a method call

Within my select element, the value is currently being assigned through an ngOnInit call. Here is an example of the HTML code: <select name="duration" [(ngModel)]="exercisePlan.duration" (ngModelChange)="onChange($event)"> <option *ngFor="l ...

Utilizing the props value for emission within the emits array: A guide

While attempting to list a custom event in the component's emits option, I encountered a console error. The code looked like this: PARENT <Btn event-name="toggleSideMenu" @toggle-side-menu="toggleHandler"> togg ...

Ensure that the cursor is consistently positioned at the end within a contenteditable div

I'm working on a project where I need to always set the caret position at the end of the text. By default, this works fine but when dynamically adding text, the caret position changes to the starting point in Chrome and Firefox (Internet Explorer is s ...

What is the best way to ensure my arrow text remains properly positioned when using fullpage.js?

Seeking guidance from the web development community. I am currently working on a client's website that utilizes fullpage.js and encountering a persistent issue. On slide1 of the website, I am struggling to display the correct text next to the arrows. ...

Disappearing modal in Bootstrap 5 does not eliminate the backdrop

When using Bootstrap 5, I create my modal like this: var myModal = new bootstrap.Modal(document.getElementById('scheduleMeetingModal'), { backdrop: 'static' }); myModal.show(); Later on, when I want to hide the modal in another fun ...

How can I connect the box using the Interactive Picture jQuery tool?

When using the Interactive picture jQuery, I have the following code snippet within my document: jQuery(document).ready(function(){ $( "#iPicture6" ).iPicture({ animation: true, animationBg: "bgblack", animationType: "ltr-slide ...

"Unlocking the Power of mediaElementjs: Easy Steps to Accessing the Player Instance

I'm facing a small issue with the MediaElement.js player. To access the player instance, I usually use the following code (which works in HTML5 compatible browsers): // Retrieve player this.playerId = $('div#shotlist-player video').att ...