Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable<{}> not assignable to type Observable<SomeType[]>

I'm learning Angular2 and Typescript. I'm working through the Heroes tutorial on angular.io, but applying it to a project I'm converting from ASP.Net. I've run into a problem which I think is due to my lack of understanding, though as far as I can see it matches what the relevant part of the tutorial is doing.

import { Injectable } from '@angular/core';
import {RiskListSummary} from '../Models/RiskListSummary';
import { Observable } from 'rxjs/Rx';
import { Http, Response } from '@angular/http';

@Injectable()
export class RiskAssessmentListService {

    constructor(private http : Http) {}

    private serviceUrl = "http://myserviceurl/";

    getRisks(): Observable<RiskListSummary[]> {
        return this.http.get(this.serviceUrl)
            .map(this.extractData())
            .catch(this.handleError());
    }

    private extractData(res: Response) {
       if (res.status < 200 || res.status >= 300) {
             throw new Error('Bad response status: ' + res.status);
           }
       let body = res.json();
       return body.data || { };
    }

    private handleError (error: any) {
        let errMsg = error.message || 'Server error';
        console.error(errMsg); // log to console instead
        return Observable.throw(errMsg);
    }
}

I'm getting the following error on the line "return this.http.get(this.serviceUrl)":

Error:(20, 16) TS2322: Type 'Observable<{}>' is not assignable to type 'Observable'. Type '{}' is not assignable to type 'RiskListSummary[]'. Property 'length' is missing in type '{}'.

If it makes a difference, I'm using webstorm (latest version), but I think this error is coming straight from the typescript compiler. I was thinking maybe I need a typings file for rxjs, but the tutorial doesn't use one, and none of the ones that I found with a "typings search" made a difference

The following are my dependencies from package.json:

  "dependencies": {
    "@angular/common":  "2.0.0-rc.1",
    "@angular/compiler":  "2.0.0-rc.1",
    "@angular/core":  "2.0.0-rc.1",
    "@angular/http":  "2.0.0-rc.1",
    "@angular/platform-browser":  "2.0.0-rc.1",
    "@angular/platform-browser-dynamic":  "2.0.0-rc.1",
    "@angular/router":  "2.0.0-rc.1",
    "@angular/router-deprecated":  "2.0.0-rc.1",
    "@angular/upgrade":  "2.0.0-rc.1",

    "systemjs": "0.19.27",
    "es6-shim": "^0.35.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12"
like image 680
Kevin O'Donovan Avatar asked May 14 '16 00:05

Kevin O'Donovan


3 Answers

I think that your problem is located here:

getRisks(): Observable<RiskListSummary[]> {
  return this.http.get(this.serviceUrl)
     .map(this.extractData()) <== passing result of function
     .catch(this.handleError()); <== passing result of function
}

You could use just passing function reference:

getRisks(): Observable<RiskListSummary[]> {
  return this.http.get(this.serviceUrl)
     .map(this.extractData)
     .catch(this.handleError);
}

but this way you will lose this.

Or you could use bind method to retain this:

getRisks(): Observable<RiskListSummary[]> {
  return this.http.get(this.serviceUrl)
    .map(this.extractData.bind(this))
    .catch(this.handleError.bind(this));
}

however you will lose type checking.

I would leverage arrow functions to be able to use lexical this:

getRisks(): Observable<RiskListSummary[]> {
  return this.http.get(this.serviceUrl)
    .map(res => this.extractData(res))
    .catch(err => this.handleError(err));
}

Without it, the this variable will point to the function where the call is made, instead of the instance that contains getRisks().

like image 182
yurzui Avatar answered Nov 08 '22 16:11

yurzui


I had same problem, however no matter how I changed as above mentioned,It still not working. Until my college found this map, catch defination as VSC prompted

so the proper change should be like (add type cast the following place)

getRisks(): Observable<RiskListSummary[]> {
  return this.http.get(this.serviceUrl)
    .map<RiskListSummary[]>(this.extractData)
    .catch<RiskListSummary[]>(this.handleError);
}

I am new to TypeScript. so this kind of [method signature] really give me a hammer on the head :(

But finally it worked out :)

like image 7
Fei Avatar answered Nov 08 '22 15:11

Fei


According to the getRisks() fn, you are types to return Observable<RiskListSummary[]>. However in your code, you are returning body.data || {}. I believe you need to interface your RiskListSummary[] to your body.data.

like image 1
Sean Larkin Avatar answered Nov 08 '22 16:11

Sean Larkin