Chart of commitments and potential outcomes

I am in the early stages of learning about promises and I am struggling to understand how to write code correctly. Here is an overview of what the program should do:

  • Retrieve a list of item types (obtained through a promise)
  • Loop through each item type to check if any item of that type matches a given ID (using another promise)
  • If a match is found, return the item type, otherwise do nothing.

Below is the code snippet:

  public getItemTypeFromItemId(itemId: string): Promise<ItemTypeName[]> {
    console.log("Searching for ID " + itemId + " in all item types");
    return this.getItemTypes().then(itemtypes => {
      console.log("Found " + itemtypes.length + " item types.")
      let itemtypenames: ItemTypeName[] = [];
      const calls = itemtypes.map(itemtype => {
        console.log("Looking in " + itemtype.name);
        return this.getItemById(itemtype.name, itemId).then(value => {
          if (value !== undefined) {
            console.log("FOUND " + itemId + " within " + itemtype.name);
            // There is an item of this type with this id
            itemtypenames.push(itemtype.name as ItemTypeName);
          }
        });
      });
      return Promise.all(calls).then(() => itemtypenames);
    });
  }

Below are automated tests outlining the expected outcomes:

  const PART_ID = "2A1499A5563349DAA1597EFB375FA8F2";
  const CAD_ID = "24FCC02F8BD048C5881E1C63DAFC88BB";

  describe('"getItemTypeFromItemId": get ItemType from item ID', async function () {
    it('Finds the correct item type when the ID is present', async function () {
      await itemTypeService.getItemTypeFromItemId(PART_ID).then(itemtypenames => expect(itemtypenames[0]).to.equal("Part"));
      await itemTypeService.getItemTypeFromItemId(CAD_ID).then(itemtypenames => expect(itemtypenames[0]).to.equal("CAD"));
    });

    it('Returns `undefined` if no item with this ID exists', async function () {
      await itemTypeService.getItemTypeFromItemId("").then(itemtypenames => expect(itemtypenames.length).to.equal(0));
    });
  });

Answer №1

Your current issue is stemming from TypeScript's inference of the return type when using Promise.all. TypeScript is interpreting the return type of your function as Promise<ItemTypeName | (ItemTypeName | undefined)[]>, which may not align with your intended outcome.

To address this and ensure the return type remains as Promise whilst handling scenarios where nothing is found, you can adopt a slightly modified approach:

public getItemByIdWithoutItemType(itemId: string): Promise<ItemTypeName | undefined> {
return this.getItemTypes().then(itemTypes => {
    const requests = itemTypes.map(itemType => {
        return this.getItemById(itemType.name, itemId).then(value => {
            if (value !== undefined) {
                return itemtype.name as ItemTypeName;
            } else {
                return undefined;
            }
        });
    });

    return Promise.all(requests).then(results => {
        const validResults = results.filter(result => result !== undefined) as ItemTypeName[];
    
        if (validResults.length > 0) {
            return validResults[0];
        } else {
            return undefined;
        }
    });
});

}

Answer №2

It seems there is some confusion regarding the purpose of the function as pointed out by other commenters. It might be more beneficial to rewrite it using async/await, which simplifies working with Promises.

UPDATE: After considering your feedback, here is a revised version that aligns more closely with your requirements:

public async fetchItemsByIdWithoutType(
  itemId: string,
): Promise<ItemType[]> {
  const itemTypes = await this.retrieveItemTypes();
  const matchedItems: ItemType[] = [];
  await Promise.all(
    itemTypes.map(async (itemType) => {
      const foundItem = await this.fetchItemById(itemtype.name, itemId);
      if (foundItem !== undefined) {
        matchedItems.push(itemType.name);
      }
    })
  );
  return matchedItems;
}

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

What sets apart the typescript@latest and typescript@next NPM packages from each other?

Can you enlighten me on the disparities between typescript@next and typescript@latest? I understand the functionality of typescript@next, yet I struggle to differentiate it from typescript@latest. From my perspective, they appear to be identical. There is ...

When executing npm release alongside webpack, an error is triggered

Currently, I am following a tutorial provided by Microsoft. You can access it through this link: https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr-typescript-webpack?view=aspnetcore-3.1&tabs=visual-studio However, when attempting to run ...

What is the best way to synchronize API definitions between the server and client using TypeScript?

My setup involves a server (TypeScript, NestJS) and a client (TypeScript, Angular) that communicate with each other. Right now, I have the API response DTO classes defined in both the server to output data and in the client to decode the responses into a ...

What could be causing the Uncaught Error to persist even after using .catch()?

Check out this code snippet: function pause(ms:number) { return new Promise((resolve:any,reject:any) => setTimeout(resolve,ms)) } async function throwError(): Promise<void> { await pause(2000) console.log("error throw") throw new ...

Dealing with client-side exceptions in a Next.js 13 application's directory error handling

After carefully following the provided instructions on error handling in the Routing: Error Handling documentation, I have successfully implemented both error.tsx and global-error.tsx components in nested routes as well as the root app directory. However, ...

Steps to set angular for all items in the dropdown menu:

I am currently working on implementing a dropdown feature within my Angular application. The dropdown will display a list of shops, and when a shop is selected, it will show the content related to that particular shop. I need to add a new item called "ALL ...

Access the data within a jsonArray using Cypress

I'm dealing with a test.json file that contains a jsonArray [{ "EMAIL": "email_1", "FIRST_NAME": "Daniel" }, [{ "EMAIL": "email_2", "FIRST_NAME": "John" }] ] I'm trying to figure out how to use cypre ...

The type 'xxxx' is not compatible with the parameter type 'JSXElementConstructor<never>'

I am currently enrolled in a TypeScript course on Udemy. If you're interested, you can check it out here. import { connect } from 'react-redux'; import { Todo, fetchTodos } from '../actions'; import { StoreState } from '../red ...

Obtaining attributes of a class from an object passed into the constructor

Consider the following code snippet: interface MyInterface { readonly valA: number; readonly valB: number; } class MyClass { readonly valA: number; readonly valB: number; constructor(props: MyInterface) { this.valA = props.val ...

Issue encountered with dynamic ngStyle variable: ERROR Error: Unable to locate a supporting object 'ngStyleSmall'

I have defined two variables for ngstyle ngStyleSmall = { width: '150px !important', 'max-width': '150px', }; ngStylemedium = { width: '250px !important', 'max-width&apo ...

The parameter type 'Event' cannot be assigned to the argument type

edit-category-component.html: <custom-form-category *ngIf="model" [model]="model" (onSaveChanges)="handleChanges($event)"></custom-form-category> <mat-loader *ngIf="!model"></mat-loader> edi ...

Facing problem with implementing NgMoudleFactoryLoader for lazy loading in Angular 8

A situation arose where I needed to lazy load a popups module outside of the regular router lazy-loading. In order to achieve this, I made the following adjustments: angular.json "architect": { "build": { ... "options": { ... "lazyM ...

Problem with Invoking method of parent component from child component in Angular 4

Despite having all my event emitters set up correctly, there's one that seems to be causing issues. child.ts: @Component({ ... outputs: ['fileUploaded'] }) export class childComponent implements OnInit { ... fileUploaded ...

Troubleshooting issue with loading local json files in Ionic 3 on Android device

Recently, I've been exploring the process of loading a local JSON data file in my project. I have stored my .json files in the /src/assets/data directory and here is the provider code snippet that I am utilizing: import { Injectable } from '@ang ...

Exploring the representation of recursive types using generic type constraints

Is there a way to create a structure that can handle recursive relationships like the one described below? I am looking to limit the types of values that can be added to a general container to either primitive data types or other containers. Due to limit ...

Using Angular BehaviorSubject in different routed components always results in null values when accessing with .getValue or .subscribe

I am facing an issue in my Angular application where the JSON object saved in the service is not being retrieved properly. When I navigate to another page, the BehaviorSubject .getValue() always returns empty. I have tried using .subscribe but without succ ...

How can I restrict the return type of a generic method in TypeScript based on the argument type?

How can we constrain the return type of getStreamFor$(item: Item) based on the parameter type Item? The desired outcome is: When calling getStream$(Item.Car), the type of stream$ should be Observable<CarModel> When calling getStream$(Item.Animal), ...

Javascript/Typescript Performance Evaluation

I am looking to create a visual report in the form of a table that displays the count of each rating based on the date. The ratings are based on a scale of 1 to 5. Below is the object containing the data: [ { "Date": "01/11/2022", ...

What are the best methods for implementing runtime type checking in JavaScript?

Utilizing either TypeScript or Facebook's Flow (type), I am empowered to statically assign types to variables like this: function add (x: integer, y: integer) { ... } Both TypeScript and Flow are able to identify and prevent incorrect invocations su ...

Error: NullInjector - The injector encountered an error when trying to inject the Component into the MatDialogRef in the AppModule

When utilizing a component via routing as well as injecting it as the "target" of a modal dialog, I encountered an issue: export class Component1 implements OnInit { constructor(private service: <someService>, public dialogRef: MatDialogRef<Compo ...