“对象"类型上不存在属性“json" [英] Property 'json' does not exist on type 'Object'

查看:36
本文介绍了“对象"类型上不存在属性“json"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 angular 2 HttpClient 通过 REST 获取数据.我正在关注这里的角度教程 https://angular.io/tutorial/toh-pt6英雄和 HTTP 部分下,您将看到这段用于通过 http 获取英雄数据的代码片段.

getHeroes(): Promise{返回 this.http.get(this.heroesUrl).承诺().then(response => response.json().data as Hero[]).catch(this.handleError);}

下面是我在我的应用程序中编写的类似版本

fetch(startIndex: number, limit: number): Promise{让 url = this.baseUrl + "&startIndex=" + startIndex + "&limit=" + limit;返回 this.http.get(url).承诺().then(response => response.json().results as Order[]).catch(this.handleError);}

我正在使用 InteliJ Idea,并且在调用 response.json() 上有一条红线,即使我尝试使用 ng build 进行构建时,我也收到错误消息.

<块引用>

对象"类型上不存在属性json".

您可能会注意到,我有 json().results 而不是 json().data.那是因为根据教程,服务器使用具有 data 字段的对象进行响应,但我自己的服务器使用具有 results 字段的对象进行响应.如果您稍微向下滚动教程,您会看到这一点.

<块引用>

注意服务器返回的数据的形状.这个特别内存中的 Web API 示例返回一个具有数据属性的对象.您的API 可能会返回其他内容.调整代码以匹配您的网络API.

为了解决这个问题,我尝试了这样的事情

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

当我这样做时,.json() 方法已解决,但又出现了另一个错误

<块引用>

属性结果在 Promise 类型上不存在

我尝试通过定义一个接口来解决这个问题

interface OrderResponse {订单:订单[];}

并将get调用修改为

 .get(url)...

但这也不起作用.又出现了一个错误

<块引用>

类型OrderResponse"不可分配给类型Response".

需要注意的一点是,在教程中他们使用了 Angular HttpModule,但在我的应用程序中我使用的是新的 Angular HttpClientModule,所以也许这就是错误所在.

我是 Angular 2 的新手,这是我用它构建的第一个应用程序.如果上面的代码对于新的 HttpClientModule 不再有效,我很感激有关如何使用新的 HttpClientModule 实现相同目标的任何帮助.

我发现了类似的问题 属性 'json' 在类型上不存在{}"对象"类型上不存在属性 但那里的答案都没有帮助我.

更新

正如评论所暗示的那样,新的 HttpClientModule 中没有 .json() 方法.我仍然很感激有关如何使用新模块实现相同效果的帮助.从指南中他们做了这样的事情

http.get('/api/items').subscribe(data => {//数据现在是 ItemsResponse 类型的实例,因此您可以这样做:this.results = data.results;});

我完全理解,但我的问题是,该代码不在组件中,而是在服务中,因此调用 subscribe 并将结果分配给实例字段没有多大意义.

我需要我的服务返回包装在 Promise 中的订单数组.我的组件可以像

一样调用

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

我也想过在我的服务获取方法中声明一个局部变量,这样我就可以了

.subscribe(data => {this.orders = data.results;}//在 get 调用中,我返回了我的局部变量订单,例如返回 Promise.resolve(orders)

但这对我来说没有多大意义,因为对 .get() 的调用是异步的,并且该方法甚至可能在获取所有数据之前就返回,并且订单数组可能为空.

更新

这里要求的是 handleError 的代码

private handleError(error: any): Promise{console.log('发生错误', 错误);返回 Promise.reject(error.message || error);}

解决方案

UPDATE: for rxjs > v5.5

正如一些评论和其他答案中提到的,默认情况下 HttpClient 反序列化一个响应对象.它的一些方法允许传递泛型类型参数以便对结果进行类型化.这就是为什么不再有 json() 方法的原因.

import {throwError} from 'rxjs';从 'rxjs/operators' 导入 {catchError, map};导出接口 Order {//特性}接口响应订单{结果:订单[];}@Injectable()导出类 FooService {ctor(私有 http:HttpClient){}fetch(startIndex: number, limit: number): Observable{让参数 = 新的 HttpParams();params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());//基本 URL 不应该有 ?在里面返回 this.http.get<ResponseOrders >(this.baseUrl,{参数}).管道(地图(res => res.results || []),catchError(error => _throwError(error.message || error)));}

请注意,只需调用 toPromise(),您就可以轻松地将返回的 Observable 转换为 Promise.

原始答案:

在你的情况下,你可以

假设您的后端返回如下内容:

{results: [{},{}]}

在 JSON 格式中,其中每个 {} 都是一个序列化对象,您需要以下内容:

//src 文件夹中的某处导出接口 Order {//特性}从@angular/common/http"导入 { HttpClient, HttpParams };从 'rxjs/Observable' 导入 { Observable };导入 'rxjs/add/operator/catch';导入 'rxjs/add/operator/map';从'somewhere_in_src'导入{订单};@Injectable()导出类 FooService {ctor(私有 http:HttpClient){}fetch(startIndex: number, limit: number): Observable{让参数 = 新的 HttpParams();params = params.set('startIndex',startIndex.toString()).set('limit',limit.toString());//基本 URL 不应该有 ?在里面返回 this.http.get(this.baseUrl,{参数}).map(res => res.results as Order[] || []);//如果 res POJO 中的属性结果不存在(res.results 返回 null)则返回空数组([])}}

我删除了 catch 部分,因为这可以通过 HTTP 拦截器存档.检查文档.例如:

https://gist.github.com/jotatoledo/765c7f6d8a755613cafca>p

而要消费你只需要像这样调用它:

//例如在某些组件中this.fooService.fetch(...).subscribe(data => ...);//数据是订单[]

I'm trying fetch data via REST with angular 2 HttpClient. I'm following the angular tutorial here https://angular.io/tutorial/toh-pt6 and under the Heroes and HTTP section you'll see this snippet of code used to fetch hero data via http.

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

And below is a similar version I wrote in my application

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);
}

I'm using InteliJ Idea and there's a red line on the call response.json() and even when I try to build using ng build I get the error.

Property 'json' does not exist on type 'Object'.

You may notice that instead of json().data I have json().results. That's because according to the tutorial the server responded with an object that has a data field but my own server responds with an object that has a results field. If you scroll down the tutorial a bit you'll see this point.

Note the shape of the data that the server returns. This particular in-memory web API example returns an object with a data property. Your API might return something else. Adjust the code to match your web API.

In an attempt to fix this, I tried something like this

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

When I did that the .json() method was been resolved but another error popped up that

Property results does not exist on type Promise

I tried fixing that by defining an interface

interface OrderResponse {
    orders: Order[];
}

And modified the get call to

 .get<OrderResponse>(url)...

But that also didn't work. Another error popped up

Type 'OrderResponse' is not assignable to type 'Response'.

One thing note is that, in the tutorial they used the Angular HttpModule but in my application I'm using the new Angular HttpClientModule so maybe that's where the error is coming.

I'm new to Angular 2 and this is the first app I'm building with it. If the above code is no longer valid with the new HttpClientModule I'd appreciate any help on how to achieve the same with the new HttpClientModule.

I found similar questions Property 'json' does not exist on type '{}' and Property does not exist on type 'object' but none of the answers there helped me.

Update

As the comments suggested there is no .json() method in the new HttpClientModule. I'd still appreciate help on how to achieve the same effect with the new module. From the guide they did something like this

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

Which I understand perfectly but my problem is, that code is not within a component but a service so calling subscribe and assigning the result to a instance field won't make much sense.

I need my service to return an array of Orders wrapped in a Promise. The my components can just make calls like

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

I also thought of declaring a local variable in my service fetch method so that I can do

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

But that doesn't make much sense to me as the call to .get() is asynchronous and the method may return even before all the data is fetch and the orders array may be empty.

Update

As requested here is the code for handleError

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

解决方案

UPDATE: for rxjs > v5.5

As mentioned in some of the comments and other answers, by default the HttpClient deserializes the content of a response into an object. Some of its methods allow passing a generic type argument in order to duck-type the result. Thats why there is no json() method anymore.

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))
    );
} 

Notice that you could easily transform the returned Observable to a Promise by simply invoking toPromise().

ORIGINAL ANSWER:

In your case, you can

Assumming that your backend returns something like:

{results: [{},{}]}

in JSON format, where every {} is a serialized object, you would need the following:

// 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 ([])
  }
} 

I removed the catch section, as this could be archived through a HTTP interceptor. Check the docs. As example:

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

And to consume you just need to call it like:

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

这篇关于“对象"类型上不存在属性“json"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆