【问题标题】:HttpClient type safety seems to ignore interfaceHttpClient 类型安全似乎忽略了接口
【发布时间】:2018-04-01 00:59:59
【问题描述】:

TL;DR:

  1. 定义了一个角度接口并将其绑定到HttpClient.get() 响应。
  2. 响应被映射到看似通用的object 类型。
  3. 诸如idtitle 之类的接口上未定义的属性可以在响应中访问,也可以从调用的.html 中访问(例如<p>Title is: {{message?.title}}</p>
  4. 如果接口是合同,它不应该阻止其中的一些吗?

来自 Java 背景的 Angular 4 新手,在 HttpClient 类型安全方面遇到了挫折。正如this guide 指出的那样,可以将一个接口传递给http.get&lt;&gt; 以对HTTP 响应进行类型检查。

考虑一个带有单个 foo 字段的基本接口:

export interface FooInterface{
   foo: string;
}

按照上述指南,这个接口可以很容易地绑定到响应:

export class RestComponent {

   message: FooInterface;

    http.get<FooInterface>('/api/items').subscribe(data => {
        this.message = data;
        console.log(this.message);
        console.log(typeof(this.message));
        console.log(this.message.foo);
    });

此时,我点击了一个没有 foo 字段的随机 API。实际的 API 有两个字段:idtitle。令我惊讶的是,当我点击这个 API 时,仍然创建了数据对象:

Data 是具有字段idtitle 的通用对象。对data.foo 的调用返回undefined

此外,虽然界面阻止我直接访问这些 idtitle 字段,但它们仍然可以通过像 data['id'] 这样的调用来使用。它们也可以在 HTML 中引用。

<h1>
  id: {{message.id}}
  <br>
  title: {{message?.title}}
</h1>

这会被渲染!事实上,界面似乎唯一能做的就是阻止我做类似的事情:

`this.message.title`

我想这很酷……但如果这些字段可以通过this.message['title'] 访问或在 html 文件中引用,那么界面的意义何在?

【问题讨论】:

  • 仅仅提供一个泛型类型并不意味着 Angular 会进行任何类型转换或验证。 "Typechecking" 可能不是文档引用此内容的最清晰方式。这只是对您有益的提示,因此您可以记录您期望收到的形状,并在随后与之交互时从编译器获得帮助。如果您需要一些转换,则必须自己编写。
  • 这就是我的感觉,但我认为界面是一种契约,而不是一种暗示。您是否推荐任何实用程序/快捷方式来进行这些转换?
  • 我不确定你从哪里得到这个想法,请注意 TS 的类型是 only 在编译时。我们只是根据需要编写了自己的映射方法;如果你想要一个图书馆,我建议你去 NPM。
  • 我想我认为我与 java 的对应关系太多了,谢谢你的澄清
  • 具有 C# 或 Java 背景的开发人员经常遇到 TS 类型的问题,这是有原因的。此外,data['id'] 是一种在需要时跳过类型检查的合法技术,并且由于明显的原因无法使用 JIT 编译器检查模板中的类型,因为它是一个被 TS 忽略的字符串——但它们肯定会被 AOT 检查.

标签: angular typescript


【解决方案1】:

当来自 Java 背景时,TypeScript 类型的一般问题是类型不是强制的。每当您在 TypeScript 中进行强制转换时,如果对象不属于该类,则不会引发运行时异常。稍后访问该对象的缺失字段时会引发异常。

您想要做的不是编译时类型检查(如 TypeScript 所做的那样),而是想要强制执行特定类型的响应。

您可以通过手动检查响应来做到这一点:

    http.get<FooInterface>('/api/items').subscribe(data => {
        if (typeof data !== 'object')
          throw new Error('Expected an object')
        if (typeof data.foo !== 'string')
          throw new Error('Expected a string property')
        this.message = data;
    });

如果您想自动执行此操作,请查看 JSON Schema 验证。除了 TypeScript 类之外,您还需要定义 JSON 模式。 a library 可以帮助您保持同步。还有一些库可以自动生成它们,例如Spring REST 端点,因此您可以使它们与您的后端服务保持同步。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2016-09-30
    • 2016-03-16
    • 2014-02-03
    • 2012-03-11
    • 2013-09-07
    相关资源
    最近更新 更多