在类型“Object”上不存在属性“json”。
在类型“Object”上不存在属性“json”。
我正在尝试使用Angular 2的HttpClient来通过REST获取数据。我正在遵循这里的Angular教程https://angular.io/tutorial/toh-pt6,在英雄和HTTP部分中,你会看到这段用于通过http获取英雄数据的代码片段。
getHeroes(): Promise{ return this.http.get(this.heroesUrl) .toPromise() .then(response => response.json().data as Hero[]) .catch(this.handleError); }
下面是我在应用程序中编写的类似版本
fetch(startIndex: number, limit: number): Promise{ 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()时出现了红线,即使我尝试使用ng build构建也会出现错误。
类型“Object”上不存在属性“json”。
你可能会注意到,我使用的是json().results
而不是json().data
。这是因为根据教程,服务器返回了一个带有data
字段的对象,但我的服务器返回了一个带有results
字段的对象。如果你向下滚动一点,你会看到这一点。
注意服务器返回的数据形状。这个特定的内存Web API示例返回一个带有数据属性的对象。你的API可能返回其他内容。调整代码以匹配你的Web API。
为了解决这个问题,我尝试了如下的代码
(response: Response) => response.json().results as Order[]
当我这样做时,.json()方法被解析了,但是又出现了另一个错误
类型“Promise”上不存在属性“results”。
我尝试通过定义一个接口来解决这个问题
interface OrderResponse { orders: Order[]; }
并将get调用修改为
.get(url)...
但是这也没有起作用。又出现了另一个错误
类型“OrderResponse”不能赋值给类型“Response”。
需要注意的一点是,教程中使用的是Angular HttpModule,但是在我的应用程序中,我使用的是新的Angular HttpClientModule,所以错误可能就出在这里。
我对Angular 2还不熟悉,这是我用它构建的第一个应用程序。如果上述代码在新的HttpClientModule中不再有效,我将非常感激如何使用新的HttpClientModule实现相同效果的任何帮助。
我在Property 'json' does not exist on type '{}'和Property does not exist on type 'object'上找到了类似的问题,但那里的答案都没有帮助到我。
更新
正如评论中建议的那样,在新的HttpClientModule中没有.json()方法。我仍然需要在新模块中如何实现相同效果的帮助。根据指南,他们做了这样的事情
http.get('/api/items').subscribe(data => { // data现在是ItemsResponse类型的一个实例,所以你可以这样做: this.results = data.results; });
我完全理解这个,但我的问题是,这段代码不是在组件中,而是在服务中,所以调用subscribe并将结果分配给一个实例字段并没有太多意义。
我希望我的服务返回一个包含在Promise中的Order数组。然后我的组件就可以这样调用
this.orderService.fetch(0, 10).then(orders => this.orders = orders)
我还考虑过在我的服务fetch方法中声明一个局部变量,这样我就可以做到
.subscribe(data => { this.orders = data.results; } // 并在get调用之外返回我的局部变量orders,如下所示 return Promise.resolve(orders)
但是对我来说这没有太多意义,因为.get()调用是异步的,方法可能在所有数据都被获取之前就返回了,orders数组可能为空。
更新
根据要求,这是handleError的代码
private handleError(error: any): Promise{ console.log('An error occured ', error); return Promise.reject(error.message || error); }
在新的HttpClient(Angular 4.3+)中,response对象默认为JSON格式,因此不再需要使用response.json().data。直接使用response即可。
解决方法是使用HttpClient替代原来的http模块,并将其注入到组件或服务中。然后在ngOnInit()方法中使用get()方法来发送GET请求,并通过subscribe()方法来订阅返回的响应。
在项目的app.module.ts中,不要忘记导入HttpClientModule,并在imports中包含它。
下面是一个修改自官方文档的示例代码:
import { HttpClient } from '@angular/common/http'; export class YourComponent implements OnInit { constructor(private http: HttpClient) {} ngOnInit(): void { this.http.get('https://api.github.com/users') .subscribe(response => console.log(response)); } }
在app.module.ts中:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ BrowserModule, HttpClientModule, ... ], ... })
这是一个简单明了的例子,说明了问题的解决方法。如果每个人都能给出这样有帮助的答案,那就太好了。
在上述内容中,出现了(Property 'json' does not exist on type 'Object')的问题。该问题的出现原因是由于HttpClient默认将响应的内容反序列化为一个对象,一些方法允许传入泛型类型参数以进行鸭式类型检查,因此就没有了json()方法。
解决方法是通过使用泛型来指定返回结果的类型。在fetch方法中,使用Observable
下面是修改后的代码示例:
import { HttpClient, HttpParams } from '/common/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/operator/map'; export interface Order { // Properties } export class FooService { constructor(private http: HttpClient) {} fetch(startIndex: number, limit: number): Observable{ let params = new HttpParams(); params = params.set('startIndex', startIndex.toString()).set('limit', limit.toString()); // base URL should not have ? in it at the end return this.http.get(this.baseUrl, { params }) .map(res => res['results'] as Order[] || []); } }
通过以上修改,可以解决(Property 'json' does not exist on type 'Object')的问题。同时,可以将返回的Observable转换为Promise,只需调用toPromise()方法。
感谢以上代码的作者提供了解决方案,并提供了一些额外的讨论和建议。以上代码已经通过测试,可以正常使用。