Seeking assistance in addressing a TypeScript error related to typecasting in Angular 9

After updating Angular from version 4 to 9, I have encountered some errors that I am struggling to resolve.

Here is a snippet of my code:

this.getTrades().then((trades) => {
    console.log(trades);
    this.trades = new MatTableDataSource<Trade>(trades);
});

getTrades() {
    let promise = new Promise((resolve, reject) => {
        this.dataService.getTrades().subscribe((trades) => {
            resolve(trades);
        });
    });
    return promise;
}

export interface Trade {
    ID: number;
    UserID: number;
    DateTime: Date;
    Exchange: Exchange;
    BaseCoin: Coin;
    MarketCoin: MarketCoin;
    Price: number;
    Amount: number;
    Total: number;
    Last: number;
    Type: Type;
    Status: Status;
    Symbol: string;
}

The function getTrades() uses the following data source:

getTrades() {

    return this.http.get('http://localhost:8888/currencytracker-api/json/get-trades.php').pipe(
    map(res => res.json()));

}

It retrieves a JSON array with the specified data fields.

This is the error message I am encountering:

ERROR in src/app/components/trades/trades.component.ts:100:68 - error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'Trade[]'. Type '{}' is missing the following properties from type 'Trade[]': length, pop, push, concat, and 26 more.

this.trades = new MatTableDataSource(trades);

If anyone can help me understand this error and how to fix it, I would greatly appreciate it. Thank you.

Update:

I initially declared the trades variable as:

Trade[]

However, I have now declared it as:

MatTableDataSource<Trade>

Answer №1

Subscribing inside a Promise callback is not considered best practice. This can potentially result in memory leaks.

If you find yourself needing to change an Observable into a Promise, you can utilize toPromise().

Consider enforcing strong typing on the getTrades() method:

getTrades(): Promise<Trade[]> {
    return this.dataService.getTrades().toPromise()      
}

Answer №2

You should provide more explicit information about the types:

Start by using the most suitable overload of HttpClient.get that requires a generic parameter and interprets the body as JSON.

This particular overload constructs a GET request, interpreting the body as a JSON object and returning the response body in a specified type.

getTrades(): Observable<Trade[]> {
    return this.http.get<Trade[]>( 'http://localhost:8888/currencytracker-api/json/get-trades.php' );
}

Next, add explicit types to the getTrades() function:

getTrades(): Promise<Trade[]> {
    const promise = new Promise<Trade[]>( ( resolve, reject ) => {
      this.dataSource.getTrades().subscribe( ( trades ) => {
        resolve( trades );
      });
    });
    return promise;
  }

Instead of converting to a promise, consider subscribing directly to the Observable returned by the dataSource for better efficiency:

this.dataSource.getTrades().subscribe( ( trades ) => {
    console.log( trades );
    this.trades = new MatTableDataSource<Trade>( trades );
});

Update:

Make sure you are using HttpClient from @angular/common/http, not from @angular/core. The @angular/http package has been deprecated with Angular 8 in favor of @angular/common/http.

https://www.npmjs.com/package/@angular/http

The package is no longer supported. Instead, use @angular/common, as mentioned in https://angular.io/guide/deprecations#angularhttp

Update 2: The issues you faced with assignment indicate that it was always incorrect. MatTableDataSource<Trade> is not equivalent to Trade[]

I suspect the reason why it worked in your old project is due to TypeScript 2.x. In TypeScript 3.x, getTrades() without explicit typing is inferred as Promise<unknown> instead of Promise<any>.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type

TypeScript 3.0 introduces a new top type called unknown. It serves as a type-safe alternative to any. While anything can be assigned to unknown, unknown itself can only be assigned to itself or another variable without any type assertions or narrowing based on control flow. Furthermore, operations on an unknown type require asserting or narrowing to a more specific type first.

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

Creating REST API Endpoint using Angular

Imagine having an Angular web app that displays a list of patients, the URL would be something like http://localhost:4200/patients. Is there a way to serve the same content (from the identical data source) in JSON format (application/json) by accessing ht ...

What sets apart ViewProviders from Services in Angular2?

Take a look at this piece of code: var SearchResultComponent = ng.core.Component({ selector: "search-result", directives: [ng.router.ROUTER_DIRECTIVES, FormComponent], viewProviders: [ng.http.HTTP_PROVIDERS], templateUrl: "componentTemplat ...

Filtering JSON data with Angular 4 input range feature

Hello there, I'm currently working on a search pipe in Angular 4 to filter company team sizes from JSON data using a range input between 0 and 100. However, I'm facing an issue with the range filter as I am relatively new to TypeScript and Angula ...

Is there a way to utilize enums containing dashes in GraphQl JS?

Unfortunately, GraphQL enums do not support the use of dashes and only accept underscores. In my current situation, I have enums that include dashes. These enums are already established and changing them would likely cause issues in areas that are difficu ...

How to update an Array<Object> State in ReactJS without causing mutation

In my program, I store an array of objects containing meta information. This is the format for each object. this.state.slotData [{ availability: boolean, id: number, car: { RegistrationNumber : string, ...

deliver a promise with a function's value

I have created a function to convert a file to base64 for displaying the file. ConvertFileToAddress(event): string { let localAddress: any; const reader = new FileReader(); reader.readAsDataURL(event.target['files'][0]); reader ...

Error message: "ExpressionChangedAfterItHasBeenCheckedError - encountered while using ngIf directive to hide/show a progress

My HTTP interceptor is set up to display a loading bar whenever an HTTP request is made: intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const dataStorageService = this.injector.get(DataStorageService); ...

Dynamically add functionality to base instance through derived class during execution

In my current project, I am dealing with a class hierarchy that looks like this: class Base { public BaseMethod() { // doesSomeStuff } } class Derived extends Base { constructor() { super(); } public DerivedMethod() { ...

To display a specific router link and its child routes, make use of the *ngIf directive

Issue: How can we display [content] in all child routes of a parent route such as <div *ngIf="router.url === '/parent/child'">[content]</div>, ensuring that content is shown in ./parent/child1, ./parent/child2, and so on? P ...

Link Array Element to [(value)] within Angular

Hey there! I'm currently working with Angular Material and dealing with an Array of products to generate a table in my template. <tbody> <tr *ngFor="let item of productArray | async; let i = index"> Within this loop, I have another l ...

Tips for individually assigning Fastify decorators within various plugins?

I'm encountering issues with typing decorators in two separate plugins (scopes): import Fastify, { FastifyInstance } from 'fastify' const fastify = Fastify() // scope A fastify.register((instance) => { instance.decorate('utilA&apo ...

Angular 2 Form Error: Control Not Found

I'm facing an issue with Angular 2 Forms where adding more than one control seems to be getting ignored. Despite following numerous guides on how to properly implement this, none of the suggested methods seem to work in my case. In my template, I hav ...

Insert discover within the tube

Can I modify the following code to add a pipe before the subscribe method that performs the find operation, so that only one panel is returned by the subscription? await this.panelService.getActivePanels() .pipe( map(activePanels => active ...

What is the best way to dynamically load content on a page when the URL changes within the same angular component?

I'm attempting to have a page load specific content when the URL changes, all within the same component. myComponent.ts ngOnInit(){ this.router.events.subscribe(res=> { if (this.router.url.split('?')[0].split("/").pop() === &ap ...

Tips on searching for an entry in a database with TypeScript union types when the type is either a string or an array of strings

When calling the sendEmail method, emails can be sent to either a single user or multiple users (with the variable type string | string[]). I'm trying to find a more efficient and cleaner way to distinguish between the two in order to search for them ...

Is there a way to easily toggle a Material Checkbox in Angular with just one click?

Issue with Checkbox Functionality: In a Material Dialog Component, I have implemented several Material Checkboxes to serve as column filters for a table: <h1 mat-dialog-title>Filter</h1> <div mat-dialog-content> <ng-container *ng ...

Customizing npm package within an Angular 13 project

Currently, I am working on an Angular application (v13.3.10) that relies on the ngx-markdown package. Unfortunately, I have encountered several bugs within this package and I am attempting to make edits locally in order to see changes reflected when runnin ...

angular-in-memory-web-api encounters a 404 error

I recently completed the heroes tour and now I am trying to work on something similar, but I seem to be having trouble understanding angular-in-memory-web-api. Here is a snippet of my code: clients-data.service.ts import { Injectable } from '@angular/ ...

Navigational module and wildcard for routes not located

I have my routing configuration structured as follows: app-routing const routes: Routes = [ { path: 'login', loadChildren: 'app/modules/auth/auth.module#AuthModule' }, { path: '', redirectTo: 'dash ...

Implementing an overlay feature upon clicking a menu item - here's how!

I am currently working on implementing an overlay that displays when clicking on a menu item, such as item 1, item 2 or item 3. I have managed to create a button (Click me) that shows an overlay when clicked. Now, I would like to achieve the same effect wh ...