由于 httpClient 响应数据数组抛出打字稿构建问题,无法构建 angular 应用程序

can't build angular app due to httpClient response data array throwing typescript build issue

你好,我已经离开编码游戏几年了,我正在 Angular 8 上加速(不喜欢它!)我可以 运行 ng serve 一切都很好,但如果我尝试构建我在这里遇到错误

userD() {
  // TODO User Angular Service will get to that later.
  var aToken = localStorage.getItem('token');
  const headers = new HttpHeaders().set("Authorization", "Bearer " + aToken);

  this.httpClient.get( 'http://127.0.0.1:8000/api/auth/user', { headers } )
  .subscribe((res: any[]) => {
    // @ts-ignore
    this.users = res.data.result; // it doesn't like the .data.result part in build
    console.log(this.users);
  });
}

我目前正在使用 //@ts-ignore,不是很理想,但我不知道为什么进入数组时会出现问题,如果我将它作为 res 就可以了。

任何信息都会对帮助我理解这一点很有帮助。谢谢。

注意:编辑 这是 json 我想提取到这个结果对象,然后在 html 中使用 For 循环 {"status":"200", "data": {"result":{"id":3,"name":"patrick lord","email" :"patrick@larvel.io","email_verified_at":null,"phone":"123456789","profilePic":71,"created_at":"2019-09-19 19:43:04 ","updated_at":"2019-09-19 19:43:04","stripe_id":null,"card_brand":null,"card_last_four":null,"trial_ends_at" :null,"gender":"male","Address1":"i don't live here S","Address2":"232","City":"Clearfield","Country":"USA","Zip_Post":"55550","YouTube"}}}

解释

JB 的 一针见血:您收到 TypeScript 错误,因为 any[] 类型 没有 data 属性;根据定义,any[] 期望 任何值 ,唯一的限制是输入必须是 Array.

类型的对象

但是为什么 build --prod 而不是 serve 中的错误?

您在 ng build --prod 上收到错误而在 ng serve 上收到 not 是因为默认 Angular 环境强制执行 strict(如“严格遵守打字和语法”)在 --prod 上,但 不会 在本地开发环境中强制执行 strict。这样一来,在清理代码以供生产使用之前,您可以在本地开发时更轻松地尝试和解决问题,在本地开发时,草率的语法不是问题。我也花了一点时间来解决这个问题,但这是一件好事 (tm) :P

理由

JavaScript 几乎可以让你做任何想做的事情:它不知道 res 会是什么样子,但它假设你知道自己在做什么,如果你说 res 将有一个名为 data 的 属性,它只是随之而来。

如果您有一个小项目,或者如果您是 唯一一个 愿意从事该项目的人,这很好,但是当项目变大,或者如果您有多个开发人员提交代码。 知道res有一个data属性,但是萨曼莎怎么知道的?

输入TypeScript

TypeScript 是 JavaScript...与类型。类型提供给定对象的 shape,因此所有相关人员(包括 TypeScript 转译器)都知道发生了什么。当您说 res: any[] 时,TS 听到的是“对象 res 将成为类型 ArrayObject”;然而,我们还没有,告诉 TS 关于数组中的成员项的任何信息,因为它不知道kind 数组 res 将会是,我们唯一可以访问的是 Array 类型本身的泛型方法和属性。

修复

那么,我们需要做什么 而不是 (res: any[]) 才能使 this.users = res.data.result; 正常工作?

为 ResponseObject 定义接口

我们需要先通过更详细的信息告诉 TS 会发生什么:

export interface ResponseObject {
  data: {
    result: {};
  }
}

现在 TS 知道有一个叫做 ResponseObjectObject 有(至少)一个 data 属性,并且 data 属性 是 本身 一个 Object 有(再次,至少)一个 属性 称为 result.

告诉 TypeScript 期待我们的 ResponseObject

我们可以像这样将它插入我们的订阅调用中:

.subscribe( (res: ResponseObject) => {
  this.users = res.data.result; // now it totally DOES like the .data.result part in build --prod!
  console.log(this.users);
});

等一下...

您可能会注意到 res 不再是 Array 类型的对象;根据你发布的代码和你说它通过 ng serve 工作的事实,听起来你期待一个单一的 ResponseObject 提供一个 UserObjects 数组作为 data.result [=138= 上的有效负载];如果是这样,上面的代码示例应该可以正常工作。

然而,如果我们的 .get() 真的 返回一个 array ResponseObjects,我们将需要做一些额外的工作。

处理 ResponseObject 数组

首先让我们更改接口声明:

export interface ResponseObject {
  status: number;  /*  It's OK to exclude things we don't need,
      but, the status property is going to come in handy when
      we eventually want to write a catch statement for cases
      when the call returns an error instead of the data we
      wanted  */
  data: {
    /*  you can also split up your interface declarations to
        make them easier to read; this has the added benefit of
        allowing us to more easily access the sub-properties of
        our payload later on  */
    result: UserObject;  /*  we're expecting a single
        UserObject per ResponseObject in this scenario,
        otherwise we'd use:  */
    // result: UserObject[];
  }
}

export interface UserObject {
  /*  remember to use the generic type names (lowercase 'string'),
      not Primitives (Capitalized 'String') in your interface
      declaration, otherwise you'll get more errors  */
  id: number;
  name: string;
  email?: string;  /*  the question mark lets you define a
    property that *may* exist, but may not.  Useful if your
    target API only includes parameters with non-null values
    in the ResponseObject   */
  // ...all the other things you want and think will exist
}

然后我们可以混淆我们的订阅调用:

.subscribe(
  // we tell subscribe that we're expecting an array of ResponseObjects
  (res: ResponseObject[]) => {
    /*  users needs to be defined as an array to hold onto
        multiple UserObjects; we're clearing it here to make
        sure we're only dealing with fresh data and specifying
        that it will be an array of type UserObject  */
    this.users: UserObject = [];

    /*  the data property isn't a property of the *array*, but
        of each array *member-item*, so we need a loop  */
    res.forEach(
      (res_item: ResponseObject) => {
        // add the response object data to our users array
        this.users.push(res_item.data.result);
    });

    // now console log should properly show our array of UserObjects!
    console.log(this.users);
  }
);

n.b., 请不要忘记将其标记为已接受的答案,事实上,满意地回答你的问题。如果有人对您的问题给出了更好或更简洁的答案,您随时可以在事后更改已接受的答案。

干杯!