简体   繁体   English

angular 属性“值”在“对象”类型上不存在

[英]angular Property 'value' does not exist on type 'Object'

In my Angular app I have an issue with the response of an API call:在我的 Angular 应用程序中,我对 API 调用的响应存在问题:

 private async getActor(actor:string) {
    const response = await this.searchActor.getActorImage(actor).toPromise()
    let actPics = []    
      for (var val of (response as any[]).value) {
        actPics.push(val.thumbnailUrl)}                   
  }

My app runs fine but I have this message in the console when I run ng serve我的应用程序运行良好,但是当我运行ng serve时,控制台中有此消息

Error: src/app/quiz-editor/actor-question/actor-question.component.ts:55:41 - error TS2551: Property 'value' does not exist on type 'any[]'.错误:src/app/quiz-editor/actor-question/actor-question.component.ts:55:41 - 错误 TS2551:“任何 []”类型上不存在属性“值”。 Did you mean 'values'?您指的是 'values' 吗?

55 for (var val of (response as any[]).value) { ~~~~~ 55 for (var val of (response as any[]).value) { ~~~~~

node_modules/typescript/lib/lib.es2015.iterable.d.ts:75:5 75 values(): IterableIterator; node_modules/typescript/lib/lib.es2015.iterable.d.ts:75:5 75 个值():IterableIterator; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'values' is declared here. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 这里声明了“值”。

When I console.log(response) I get:当我console.log(response)我得到:

控制台日志(响应)

I did some research and I read that I should declare response but how should I do it?.我做了一些研究,我读到我应该声明response ,但我应该怎么做呢?

I've tried this solution:我试过这个解决方案:

private async getActor(actor:string) {
    const response: { value:any[] } = await this.searchActor.getActorImage(actor).toPromise()
    let actPics = []      
    for (let val of response.value) {
      actPics.push(val.thumbnailUrl)}
}

But now I have this error:但现在我有这个错误:

 Error: src/app/quiz-editor/actor-question/actor-question.component.ts:55:11 - error TS2696: The 'Object' type is assignable to very few other types. Did you mean to use the 'any' type instead?
      Property 'value' is missing in type 'Object' but required in type '{ value: any[]; }'.

55     const response: { value:any[] } = await this.searchActor.getActorImage(actor).toPromise()
             ~~~~~~~~

  src/app/quiz-editor/actor-question/actor-question.component.ts:55:23
    55     const response: { value:any[] } = await this.searchActor.getActorImage(actor).toPromise()
                             ~~~~~
    'value' is declared here.

As your log statement shows, your response is an object containing value as a key.正如您的日志语句所示,您的response是一个包含value作为键的 object。 As such, you can do the following:因此,您可以执行以下操作:

const response: { value: any[] } = await this.searchActor.getActorImage(actor).toPromise();
let actPics = [];
for (let val of response.value) {
  actPics.push(val.thumbnailUrl);                   
}

You have to tell typescript what type your array is.您必须告诉 typescript 您的阵列是什么类型。 By saying response as any[] the compiler does not know which objects your array contains.通过说response as any[]编译器不知道您的数组包含哪些对象。 It may work at runtime, because typescript then "finds" the requested property.它可能在运行时工作,因为 typescript 然后“找到”请求的属性。 So what you should do, is create a class/interface to define the object, that you expect to receive from your API and then parse the response to it.所以你应该做的是创建一个类/接口来定义你希望从你的 API 接收到的 object,然后解析对它的响应。

Example:例子:

private async getActor(actor:string) {
const response = await this.searchActor.getActorImage(actor).toPromise();
const images = response as actorImage[];
let actPics = [];    
  for (var val of images) {
    actPics.push(val.thumbnailUrl)}                   

} }

interface actorImage{
  thumbnailUrl: string   
}

You are declaring response as an array of type any , which is incorrect.您将response声明为any类型的数组,这是不正确的。 response is not an array, response.value is an array. response不是数组, response.value是数组。 The any keyword tells typescript to not bother with type checking. any关键字告诉 typescript 不要打扰类型检查。 From the docs :文档

In some situations, not all type information is available or its declaration would take an inappropriate amount of effort.在某些情况下,并非所有类型信息都可用,或者它的声明会花费不适当的努力。 These may occur for values from code that has been written without TypeScript or a 3rd party library.这些可能发生在没有 TypeScript 或第 3 方库的情况下编写的代码中的值。 In these cases, we might want to opt-out of type checking.在这些情况下,我们可能希望选择退出类型检查。 To do so, we label these values with the any type为此,我们将 label 这些值与任何类型

So, the quick and dirty fix is to tell typescript that response is of type any doing something like this:因此,快速而肮脏的解决方法是告诉 typescript response类型为any ,执行如下操作:

 private async getActor(actor:string) {
    const response = await this.searchActor.getActorImage(actor).toPromise()
    let actPics = []    
      for (var val of (response as any).value) {
        actPics.push(val.thumbnailUrl)}                   
  }

Another perhaps more Angular-correct way of doing things would be to create a model and use that as your type.另一种可能更适合 Angular 的做事方式是创建 model 并将其用作您的类型。 Here's a stripped-down model:这是一个精简的 model:

export class ImageSearchResult {
    // you could/should type this as well instead of being an array of 
    // type any. It might be something like value: []ImageData;
    value: []any; 
}

Then, you use your model type instead of any:然后,您使用 model 类型而不是任何类型:

 private async getActor(actor:string) {
    const response = await this.searchActor.getActorImage(actor).toPromise()
    let actPics = []    
      for (var val of (response as ImageSearchResult).value) {
        actPics.push(val.thumbnailUrl)}                   
  }

But going even further, your service should return the correct type.但更进一步,您的服务应该返回正确的类型。 It's not the job of modules that consume services to type the data returned by services.输入服务返回的数据不是使用服务的模块的工作。 Also - I am assuming you are returning an observable .另外-我假设您要返回一个observable Why call toPromise ?为什么调用toPromise Let's create a service function that uses Angular's http service and returns an observable of the correct type.让我们创建一个服务 function,它使用 Angular 的 http 服务并返回一个正确类型的 observable。 You probably have something like this already:你可能已经有了这样的东西:

  import { HttpClient } from '@angular/common/http';
  
  constructor(private http: HttpClient) { }

  /**
   * Search for images by actor. Returns an observable of type ImageSearchResult.
   * @param actor The name of the actor you want to search
   */
  getActorImage(actor: string): Observable<ImageSearchResult> {
    // Refactor to appropriate http action type (post/push/etc) and url.
    return this.http.get<ImageSearchResult>(`https://my-api.com/actor-search?q=${actor}`);
  }

Then to consume this service function:然后消费这个服务function:

private getActor(actor:string) {
  this.searchActor.getActorImage(actor).subscribe(response => {
    let actPics = []
    // No casing necessary, response is already correct type.
    for (var val of response.value) {
      actPics.push(val.thumbnailUrl)
    }
  });
}

Finally, it looks like you were possibly trying to use the Azure image search API.最后,看起来您可能正在尝试使用 Azure 图像搜索 API。 In that case, take a look at how they type the return objects for inspiration .在这种情况下,看看他们如何键入返回对象以获得灵感 Depending on your project's license, you could probably just import that project and use their models with your services.根据您项目的许可证,您可能只需导入该项目并将其模型与您的服务一起使用。

You're wrongfully trying to define the response as an array.您错误地尝试将response定义为数组。 Javascript Array obviously does not have value property or method. Javascript Array显然没有value属性或方法。 You need to define the following interface instead.您需要改为定义以下接口。

export interface IResponse {
  currentOffset: number;
  instrumentation: any;
  nextOffset: number;
  queryContext: any;
  readLink: string;
  totalEstimatedMatches: any;
  value: Array<any>;
  webSearchUrl: string;
  _type: string;
}

In an ideal case, you would also define similar interfaces for instrumentation , queryContext and totalEstimatedMatches as well as for the object contained in the value array and use them instead of using any .在理想情况下,您还将为instrumentationqueryContexttotalEstimatedMatches以及包含在value数组中的 object 定义类似的接口,并使用它们而不是使用any

Additionally you don't need an explicit loop to get an array of values from an object.此外,您不需要显式循环来从 object 获取值数组。 You could use Array#map method instead.您可以改用Array#map方法。

export interface IResponse {
  currentOffset: number;
  instrumentation: any;
  nextOffset: number;
  queryContext: any;
  readLink: string;
  totalEstimatedMatches: any;
  value: Array<any>;
  webSearchUrl: string;
  _type: string;
}

@Component({...})
export class SomeComponent implements OnInit, OnDestroy {
  private async getActor(actor:string) {
    const response: IResponse = await this.searchActor.getActorImage(actor).toPromise();
    let actPics: Array<string> = response.value.map(val => val['thumbnailUrl']);
  }
}

Further remarks:补充说明:

  1. Try to use the RxJS observable without converting it to a Promise.尝试使用可观察的 RxJS 而不将其转换为 Promise。 Observables provides a range of advantages over Promises. Observables 提供了一系列优于 Promises 的优势

  2. toPromise() method will be deprecated in RxJS 7 and will be gone in RxJS 8. toPromise()方法将在 RxJS 7 中弃用,并将在 RxJS 8 中消失。

The error is cause by the fact that you are casting the response to "any[]".该错误是由于您将响应投射到“any []”而引起的。 => You hase 2 solutions: => 你有 2 个解决方案:

  1. you remove the casting (it is not necessary):您删除铸件(没有必要):

    private async getActor(actor:string) { const {value} = await this.searchActor.getActorImage(actor).toPromise() const actPics = value.map(val => val.thumbnailUrl) private async getActor(actor:string) { const {value} = await this.searchActor.getActorImage(actor).toPromise() const actPics = value.map(val => val.thumbnailUrl)
    } }

  2. You declare an interface representing the type of your API response您声明一个接口,表示您的 API 响应的类型

You just need to change the type of你只需要改变类型

const response:{value:any[]}

or或者

const response:any

both will work两者都可以

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM