【问题标题】:Array of Elements doesn't get populated by an interface元素数组不会被接口填充
【发布时间】:2019-03-05 20:23:25
【问题描述】:

我在 Angular 中提出以下请求并将响应保存在变量中:

conversations: Conversation[];

// ChatService
getConversations() {
    return this.http.get<Conversation[]>('/chat/conversations');
}

this.chatService.getConversations().subscribe(
    (response: Conversation[]) => this.conversations = response
);

这是来自服务器的 JSON 数据:

[  
   {  
      "chatRoomId":"096b8be1-2411-4cb1-94e0-ed96c51c23d8",
      "name":"Bar",
      "profilePicture":"...",
      "conversation":[  
         {  
            "name":"Bar",
            "message":"Hello!",
            "createdAt":"2018-09-30T06:50:49.000+0000"
         },
         {  
            "name":"Foo",
            "message":"Hi",
            "createdAt":"2018-09-30T11:49:05.000+0000"
         }
      ]
   }
]

TypeScript 模型:

export interface Conversation {
  chatRoomId: string;
  name: string;
  profilePicture: string;
  conversation: ChatMessage[]
}

export interface ChatMessage {
  name: string;
  message: string;
  createdAt: string;
}

问题:

如果我在控制台中输出变量,则对话(conversation: ChatMessage[])是一个空数组元素。

如果我使用this.http.get&lt;any&gt;('...') 发出请求,对话将按预期存储。

【问题讨论】:

  • 你的模板代码中有changeDetection: ChangeDetectionStrategy.OnPush吗?
  • 你在控制台输出哪个变量?
  • @Radik 是的,我收到的数据保存在我订阅的 BehaviorSubject 中。
  • @billyjov 出于调试目的,变量对话。
  • 如果您使用any 类型的响应会发生什么?

标签: arrays json angular typescript


【解决方案1】:

有几种方法可以做你想做的事,但根据我的经验,使用这个库是最简单的:https://github.com/typestack/class-transformer

以下是它在您的情况下的工作方式。首先,我会将您的接口更改为 Typescript 类。

import { Type } from 'class-transformer';

export class Conversation {
    chatRoomId: string;
    name: string;
    profilePicture: string;

    @Type(() => ChatMessage)
    conversation: ChatMessage[]

    constructor(args: Conversation) {
      Object.assign(this, args);
    }
}

export class ChatMessage {
    name: string;
    message: string;
    createdAt: string;

    constructor(args: ChatMessage) {
      Object.assign(this, args);
    }
}

与这些接口相比,一些事情发生了变化::

  1. @Type 装饰器的使用来自 class-transformer 模块。这允许您转换嵌套对象。这是文档:https://github.com/typestack/class-transformer#working-with-nested-objects
  2. 我们添加了constructor,它允许您创建这些类的实例并将属性传递给它们各自类型的属性。看看这篇Converting httpClient answer to model objects [Angular 6] 的帖子,因为它更能说明这里发生的事情。

那么在您的服务中,您的代码是这样变化的:

import { plainToClass } from 'class-transformer';    

conversations: Conversation[];

// ChatService
getConversations() {
    return this.http.get<Conversation[]>('/chat/conversations');
}

this.chatService.getConversations().subscribe(
    (response: Conversation[]) => {
        this.conversations = plainToClass(Conversation, response) as Conversation[]
    }
);

plainToClass 将获取原始 JSON 响应并将其转换为对话类的实例。如果您 console.log out this.conversations 您将看到它返回一个对话数组,每个对话都有一个名为 conversations 的 ChatMessage 类型的数组属性。

【讨论】:

  • 这篇文章完全具有误导性。上述内容均不符合问题。接口在运行时不做任何事情(确切地说,它们甚至在运行时都不存在) - 将类型更改为 any 不会改变运行时体验 - 永远。您说的是 TypeScript 检查 JSON 响应,但 TypeScript 在运行时不做任何事情,它是一个转译器。
  • @PatrickKelleter 现在看起来怎么样?你是对的,打字稿不做任何运行时类型检查,这是我的坏事。我会在这里使用 Javascript 类,因为它允许您组织服务响应 json 并明确定义嵌套类。
  • 我不能说使用类是错误的——但我可以说我实际上尽可能喜欢接口而不是类。有很多原因——这个评论太多了——但最重要的一个是我不喜欢 oop 的想法(就像现在许多其他人一样),因为类型安全,在类上使用接口更容易,也更简洁,所以如果您不使用 oop,您可能只在 90% 的时间内使用接口。类肯定有用例,但我会说它们与接口相比大约是 10%
  • btw 值得一提的是,我一开始就经常使用类(typescript 1.1 是我开始使用它的时候),因为我来自 java 并且习惯了这种设计模式。但随着时间的推移,我用接口和类型定义替换了越来越多的代码。如果你坚持那个范式,代码会变得更精简。实际上有很多比较类/接口/类型的博客文章,你可以在谷歌上试一试。打字稿文档也非常有见地,我个人从该来源以及如前所述的博客文章中学到了很多东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多