1. ホーム
  2. angular

[解決済み] プロパティ 'json' はタイプ 'Object' に存在しません。

2022-02-10 22:21:28

質問

angular 2のHttpClientでREST経由でデータを取得しようとしています。私はここでangularチュートリアルに沿っています。 https://angular.io/tutorial/toh-pt6 で、その下の ヒーローとHTTP のセクションでは、http経由でヒーローのデータを取得するために使用されるコードの断片を見ることができます。

getHeroes(): Promise<Hero[]> {
  return this.http.get(this.heroesUrl)
         .toPromise()
         .then(response => response.json().data as Hero[])
         .catch(this.handleError);
}

そして以下は、私のアプリケーションに書いた同様のバージョンです。

fetch(startIndex: number, limit: number): Promise<Order[]> {
    let url = this.baseUrl + "&startIndex=" + startIndex + "&limit=" + limit;

    return this.http.get(url)
                .toPromise()
                .then(response => response.json().results as Order[])
                .catch(this.handleError);
}

InteliJ Ideaを使っているのですが、response.json()の呼び出しに赤線が入ってしまい、response.json()でビルドしようとしても ng ビルド エラーが出ます。

プロパティ 'json' はタイプ 'Object' に存在しません。

の代わりに json().data 私は json().results . それは、チュートリアルによると、サーバーはオブジェクトで応答し、そのオブジェクトは data フィールドを持つオブジェクトで応答しますが、私自身のサーバーは、そのオブジェクトが results フィールドがあります。チュートリアルを少し下にスクロールすると、この点がわかります。

<ブロッククオート

サーバーが返すデータの形状に注目してください。この特定の in-memory Web APIの例では、dataプロパティを持つオブジェクトを返します。あなたの APIは他のものを返すかもしれません。あなたのウェブページに合うように、コードを調整してください。 APIを使用します。

これを解決するために、次のようなことを試してみました。

(response: Response) => response.json().results as Order[]

その結果、.json()メソッドは解決されましたが、別のエラーが表示され、次のようになりました。

Promise型にプロパティresultsが存在しない

インターフェイスを定義することで、それを解決しようとしました。

interface OrderResponse {
    orders: Order[];
}

そして、getコールを次のように修正しました。

 .get<OrderResponse>(url)...

しかし、これもうまくいかなかった。別のエラーが表示されました。

タイプ 'OrderResponse' はタイプ 'Response' に割り当てることができません。

チュートリアルではAngular HttpModuleを使用していますが、私のアプリケーションでは新しいAngular HttpClientModuleを使用しているので、もしかしたらそこでエラーが発生しているのかもしれませんね。

私はAngular 2の初心者で、これはAngular 2で作る最初のアプリです。もし上記のコードが新しいHttpClientModuleではもう有効でないなら、新しいHttpClientModuleで同じことを達成する方法について、何か助けをいただければ幸いです。

似たような質問を見つけました プロパティ 'json' がタイプ '{}' に存在しません。 そして プロパティがタイプ 'object' に存在しない が、どの回答も私には役に立ちませんでした。

更新情報

コメントで示唆されたように、新しいHttpClientModuleには.json()メソッドがありません。私はまだ新しいモジュールで同じ効果を達成する方法についての助けをお願いします。ガイドから彼らは次のようなことをしました。

http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

しかし、このコードはコンポーネントではなく、サービスの中にあるため、subscribeを呼び出し、その結果をインスタンスフィールドに代入してもあまり意味がないのです。

私のサービスは、Promiseに包まれたOrdersの配列を返す必要があります。私のコンポーネントは、次のような呼び出しを行うだけです。

this.orderService.fetch(0, 10).then(orders => this.orders = orders)

また、サービスのフェッチメソッドでローカル変数を宣言して、次のようなことができるようにしようと思いました。

.subscribe(data => {
    this.orders = data.results;
}
// and out of the get call I return my local variable orders like
return Promise.resolve(orders)

しかし、.get()の呼び出しは非同期であり、すべてのデータを取得する前にメソッドが戻り、orders配列が空になる可能性があるため、私にはあまり意味のないことです。

更新

ご要望にお応えして、handleErrorのコードを掲載します。

private handleError(error: any): Promise<any> {
    console.log('An error occured ', error);
    return Promise.reject(error.message || error);
}

解決方法は?

UPDATE: rxjs > v5.5用

いくつかのコメントや他の回答にもあるように、デフォルトでは HttpClient は、レスポンスの内容をオブジェクトにデシリアライズします。そのメソッドのいくつかは、結果をダックタイプ化するために一般的な型の引数を渡すことができます。そのため json() メソッドはなくなりました。

import {throwError} from 'rxjs';
import {catchError, map} from 'rxjs/operators';

export interface Order {
  // Properties
}

interface ResponseOrders {
  results: Order[];
}

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get<ResponseOrders >(this.baseUrl,{
       params
    }).pipe(
       map(res => res.results || []),
       catchError(error => _throwError(error.message || error))
    );
} 

を簡単に変換できることに注意してください。 ObservablePromise を呼び出すだけで toPromise() .

オリジナルの回答です。

あなたの場合、以下のようになります。

バックエンドが次のようなものを返すと仮定して。

{results: [{},{}]}

をJSON形式({}はすべてシリアライズされたオブジェクト)にする場合、以下のようになります。

// Somewhere in your src folder

export interface Order {
  // Properties
}

import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { Order } from 'somewhere_in_src';    

@Injectable()
export class FooService {
 ctor(private http: HttpClient){}

 fetch(startIndex: number, limit: number): Observable<Order[]> {
    let params = new HttpParams();
    params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());
    // base URL should not have ? in it at the en
    return this.http.get(this.baseUrl,{
       params
    })
    .map(res => res.results as Order[] || []); 
   // in case that the property results in the res POJO doesnt exist (res.results returns null) then return empty array ([])
  }
} 

HTTPインターセプターでアーカイブされる可能性があるので、catchセクションを削除しました。チェック ドキュメント . 例として

https://gist.github.com/jotatoledo/765c7f6d8a755613cafca97e83313b90

そして、消費するには、このように呼び出すだけでよいのです。

// In some component for example
this.fooService.fetch(...).subscribe(data => ...); // data is Order[]