【问题标题】:How do I map http request response to my defined object in TypeScript如何将 http 请求响应映射到我在 TypeScript 中定义的对象
【发布时间】:2019-01-30 03:08:07
【问题描述】:

我开始了解 Angular、TypeScript 和 RxJS。 我有一个返回 JSON 的 http 请求。在这个 JSON 中,我需要构建我定义的对象的数据。假设我的对象是这样的:

export class RegularUser {
    constructor(
        public id: number,
        public firstName: string,
        public lastName: string,
        public token: string
    ) {}
}

现在,我正在向某个 API 发送一个请求,它以这种格式返回数据:

{
    success: boolean,
    uid: number,
    first_name: string,
    last_name: string,
    cid: number,
    rights: number[]
    token: string
}

我有 HttpClient 服务,所以我想我会这样做:

this.httpClient.get(
    'http://api.example.com/api/get_user'
).pipe(
    tap((receivedData: Response) => console.log(receivedData)),
    map((receivedData: Response) => {
        return new RegularUser(
            receivedData.uid, 
            receivedData.first_name, 
            receivedData.last_name, 
            receivedData.token);
    })
);

但是对于 TypeScript,receivedData 对象没有上面列出的参数。我是否必须为 API 响应创建一个接口,然后将其映射到我的 RegularUser 对象?

【问题讨论】:

    标签: angular typescript interface rxjs


    【解决方案1】:

    您可以为get() 指定type,例如接口。为什么在您的情况下可能需要中间/附加接口来分离关注点是get() 的类型将不会新建RegularUser 类的实例。可以使用您期望从服务器响应中获得的属性创建中间/附加接口,这些属性将用于创建最终类的实例:

    interface Foo {
      uid: number,
      first_name: string,
      last_name: string,
      token: string
    }
    
    this.httpClient.get<Foo>(
        'http://api.example.com/api/get_user'
    ).pipe(
        tap((receivedData: Foo) => console.log(receivedData)),
        map((receivedData: Foo) => {
            return new RegularUser(
                receivedData.uid, 
                receivedData.first_name, 
                receivedData.last_name, 
                receivedData.token);
        })
    );
    

    如果您不需要新建类RegularUser 的实际实例,只需将其作为具有属性的接口或类就足够了:

    this.httpClient.get<RegularUser>(
        'http://api.example.com/api/get_user'
    ).pipe(
        tap((receivedData: RegularUser) => console.log(receivedData))
    );
    

    希望对您有所帮助!

    【讨论】:

    • 感谢您的回答。我需要一个RegularUser 对象的实例来共享它,所以你的第一个选择似乎更好。但是,据我了解,您的 User 接口应该有其他属性,对吧?
    • 我只添加您从服务器响应中特别需要的任何属性,不多不少。您始终可以记录响应并添加附加到该对象的任何其他内容,但我个人只是针对您需要使用的数据结构。
    【解决方案2】:

    使用接口代替构造函数,这是一个更好的选择。因此 IDE 可以使用语言服务启用代码自动补全,并且可以避免属性的错误命名。

    export interface RegularUser {
        success: boolean;
        uid: number;
        first_name: string;
        last_name: string;
        cid: number;
        rights: number[];
        token: string;
    }
    

    在役:

    this.httpClient.get<RegularUser>(
        'http://api.example.com/api/get_user'
    ).pipe(
        tap((receivedData: RegularUser) => console.log(receivedData))
    );
    

    【讨论】:

    • 感谢您的回答。我知道通过这种方法,我将通过 Angular 完成映射,但我实际上需要一个 RegularUser 对象的实例才能共享它。我希望它只有我定义的参数。
    【解决方案3】:

    您可以使用以下方法创建自己的Response 接口:

    export interface MyResponse {
      success: boolean,
      uid: number,
      first_name: string,
      last_name: string,
      cid: number,
      rights: number[]
      token: string
    }
    

    然后将其导入您的服务:

    import { MyResponse } from '../some/path/filename.ts'; 
    

    但您也可以将其包含在您的服务本身中,因此您可以跳过'export'

    您可以像当前的Response 界面一样使用它:

    (receivedData: MyResponse)
    

    注意:你可以给它任何你想要的名字(使用 TitleCase 保持一致)。您也可以使用 Angular 已经使用的名称,然后这些名称将被覆盖,但不建议这样做。见 cmets。


    您可能必须将某些属性设为可选 (?:),否则如果未使用所有属性,您可能会看到一条红线,指示“缺少某些属性”:

    ...
    success?: boolean,
    ...
    

    或者,您可以通过输入 any 来删除警告,但不建议这样做:

    (receivedData: any)
    

    【讨论】:

    • 感谢您的回答。所以我必须创建一个接口。我可以在有此 http 请求的服务文件中执行此操作吗?还有,接口的名字不应该是Response吧?
    • 更新了,你去吧。
    • 小心将接口命名为 Reponse,因为 Angular 的 HttpClient Response 可能会被 IDE 意外拉入现有的 HttpClient 导入中,或者如果需要 HttpClient Response,则需要为其设置别名如果两者都存在于同一个文件中。
    【解决方案4】:
    //Hey Guys I also Gained this problem then I'm trying this
    
    import {Component, OnInit} from '@angular/core';
    import {UserDetailsService} from './user-details.service';
    import {ApiResponse} from '../app.component';
    import {HttpClient} from '@angular/common/http';
    
    @Component({
      selector: 'app-account',
      templateUrl: './account.component.html',
      styleUrls: ['./account.component.css']
    })
    export class AccountComponent implements OnInit {
      userProfile: UserProfile;
    
      // updateSuccess: UpdateSuccess;
      constructor(
        private userDetailsService: UserDetailsService,
        private httpClient: HttpClient
      ) {
      }
    
      ngOnInit() {
        this.userDetailsService.getUserAccount().subscribe((response: ApiResponse<UserProfile>) => {
          this.userProfile = response.payload;
        });
      }
    }
    
    export interface UserProfile {
      firstName: string;
      lastName: string;
      email: string;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-08-08
      • 2011-01-10
      • 2017-10-27
      • 2014-01-21
      • 2014-03-04
      • 1970-01-01
      • 2017-03-13
      • 2017-08-02
      • 1970-01-01
      相关资源
      最近更新 更多