2

I have this piece of code that works just fine in Angular 5 but I'm trying to update to Angular 8:

  this.awsService.getProfiles().subscribe(profiles => {
    this.profiles = profiles;
    if (this.profiles.length > 0 && this.profiles.indexOf(this.currentProfile) == -1) {
      this.currentProfile = this.profiles[0];
      localStorage.setItem('profile', this.currentProfile);
    }
  }, err => {
    this.profiles = [];
  })

And I'm getting this error:

ERROR in app/app.component.ts:85:9 - error TS2696: The 'Object' type is assignable to very few other types. Did you mean to use the 'any' type instead?
  Type 'Object' is missing the following properties from type 'string[]': length, pop, push, concat, and 26 more.

85         this.profiles = profiles;

What would be the correct syntax in Angular 8?

Luis Cosio
  • 29
  • 1
  • 1
  • 3
  • 1
    What's the return type for `getProfiles()`. – Reactgular Sep 30 '19 at 13:38
  • Don't use `Object` to assert type (See [docs](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html)). – nash11 Sep 30 '19 at 13:39
  • Are you sure the code is complaining about this piece of code? The message says that you assigned the type Object to some attribute and this is very generic and you must use any for that case. – Ricardo Ferreira Sep 30 '19 at 13:58

2 Answers2

11

I have this piece of code that works just fine in Angular 5 but I'm trying to update to Angular 8:

Rxjs changed from version 5 to version 6 during your upgrade. This change had an impact on how types are handled by TypeScript, because version 6 does a better job at inferring types.

this.awsService.getProfiles().subscribe(....)

One of the big changes between Angular 5 towards Angular 6 was the switch from HttpModule to the new HttpClientModule, and this module introduced seraizlied JSON support.

For example;

  function getProfiles() {
     return this.http.get<MyInterfaceType>(....);
  }

In the above, the GET request will deserialize the JSON object into the interface type MyInterfaceType.

This feature, is not directly added to your source code when you completed the automated upgrade. So you likely have some older style code like this.

   function getProfiles() {
       return this.http.get(....);
   }

This introduces a number of type challenges for TypeScript.

  • there is no declared return type for the function and it has to be inferred
  • the return type for http.get() is an Observable<Response> type and not the JSON type

And I'm getting this error:

The fact that the error relates to an ambigious Object type implies that you haven't updated the code for awsService() to properly use the new HttpClientModule, and you haven't defined a proper return type for getProfiles().

There are a couple of approaches here:

  • define a return type for the getProfiles(): Observable<any[]> to silence the error, but this might not give you runnable code.
  • update the HTTP to serialize to JSON objects by defining the type as http.get<Profile[]>(...) as an example
  • define a parameter type for the subscribe((profiles: any[]) => {...})

Either way, I don't think you're all the way there with your upgrade.

It's easier to try and get your unit tests working, then trying to get your entire application running. While you can silence some of these TypeScript errors. It's unclear from the question if it's a symptom of the code, an upgrade issue or just a mismatched type.

Reactgular
  • 43,331
  • 14
  • 114
  • 176
  • 1
    ejem, really NOT deserialize the data. this help you to write code, but no more (and no less), simple use `.subscribe((profiles:any[])=>{..})` to say Angular that is an array – Eliseo Sep 30 '19 at 14:22
1

You could define a type or interface for your profiles instead of using Object which is very generic and won't help you much understanding the structure of your data (it only has JS generic Object's properties, like toString and haveOwnProperty).

export type Profiles = {
  property1: string;
  property2: number;
  // ...
}

// OR

export interface Profiles {
  property1: string;
  property2: number;
  // ...
}

And if this.awsService.getProfiles() already has a return type, string[] it seems, you should let TypeScript assert the type automatically or define a type Profiles equaling to string[]:

export type Profiles = string[];
// ...
public profiles: Profiles;

Or directly tell Typescript that this.profiles has string[] type:

public profiles: string[];
Guillaume
  • 6,017
  • 2
  • 21
  • 22