【问题标题】:Optimise JSON to Typescript Map优化 JSON 到 Typescript 映射
【发布时间】:2020-07-20 12:01:00
【问题描述】:

我将一个对象从 Java 传递到具有“地图”属性的 Typescript。我的打字稿模型是由接口而不是类来描述的:

export interface Foo {
    bar: Map<string, Bar>;
    mapOfBar: Map<string, Map<string, Bar>>;
}

export interface Bar {
    someField: string;
}

我编写了查询 JSON 对象并将其转换为 Foo 的代码:

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

    getFoo(): Observable<Foo> {
        return this.http.get<Foo>('/some/route/to/FooEndpoint');
    }    
}

这将返回对象,但 barmapOfBar 是对象类型,而不是 Map。所以在网上搜索了很多之后,我想出了这个代码:

    getFoo(): Observable<Foo> {
        return this.http
            .get<Foo>('/some/route/to/FooEndpoint')
            .pipe(
                map((res: Foo) => {
                    res.bar = new Map(Object.entries(res.bar));

                    let actualMapOfBar = new Map(Object.entries(res.mapOfBar));
                    res.mapOfBar = new Map();
                    for (let [key, bar] of actualMapOfBar) {
                        res.mapOfBar.set(key, new Map(Object.entries(bar)));
                    }

                    return res;
                })
            );
    }

这会将barmapOfBar 作为地图返回给我,这很棒。

称我为完美主义者,但不知何故这让人觉得笨拙和错误:

  • map((res: Foo) =&gt; { 行表明res 已经实现了Foo 接口,但它没有——它只包含属性,但不包含正确的类型(还)。
  • 这需要设置相当多的转换逻辑,尤其是在处理深度嵌套的对象树时。

有没有更简单的方法来实现这一点,或者可以优化吗?理想情况下,是否有一些“自动”的方式使用 Typescript 接口来转换对象?

(Angular 9.1,Typescript 3.8,rxjs 6.5)

编辑: 这是端点返回的示例响应:

{"bar":{"key1":{"someField":"A"},"key2":{"someField":"B"},"key3":{"someField":"C"}},"mapOfBar":{"A":{"key1":{"someField":"A"},"key2":{"someField":"B"},"key3":{"someField":"C"}},"B":{"key1":{"someField":"A"},"key2":{"someField":"B"},"key3":{"someField":"C"}},"C":{"key1":{"someField":"A"},"key2":{"someField":"B"},"key3":{"someField":"C"}}}}

【问题讨论】:

    标签: json angular typescript rxjs


    【解决方案1】:

    不,没有。 map((res: Foo) 行是-你-告诉编译器:“嘿,这是'Foo'类型”,编译器接受这个,因为他信任你。但是,您对编译器撒了谎,因为 API 的响应只是一个普通的 JSON 对象。这不能包括Map 或任何其他类。

    就像我之前说的,没有自动的方法来进行转换。你必须自己做这件事。这意味着,为了使其类型安全,您应该有两个接口。一种是FooResponse,另一种是您希望将此Foo 转换为的一种。这不存在的原因是因为TypeScript 类型仅在编译时存在。在运行时,因此当您消化 API 时,类型会丢失,您的转换信息也会丢失。这就是为什么您必须手动执行此操作的原因。

    一个小问题。为什么要它们成为地图?除了一些相对方便的 API,你也可以保持原样,将你的类型改为:

    export interface Foo {
        bar: Record<string, Bar>;
        mapOfBar: Record<string, Record<string, Bar>>;
    }
    
    export interface Bar {
        someField: string;
    }
    

    【讨论】:

    • 感谢您的详细回答,这真的很有帮助。你是对的,我使用 Map 是因为有用的辅助方法。但是,正如您所说,在这种情况下使用 Record 更有意义,因为我不需要进行手动转换。
    【解决方案2】:

    有没有更简单的方法来实现这一点,或者可以优化吗?理想情况下,是否有一些“自动”的方式使用 Typescript 接口来转换对象?

    是的,是的!它被称为 tapi.js - 它是一个轻量级的自动映射器来/从 JSON 数据。

    npm i -D tapi.js
    

    然后您可以通过多种方式映射您的对象,即:

    let typedObject = new YourClass().fromJSON(jsonData);
    

    或者,更简单地说,您可以像这样映射承诺的内容

    http.YOUR_REQUEST_CODE_HERE
        .as(YourClass)
        .[then/pipe/whatever](typedObject => { ... })
    

    您可以阅读the docs 了解更多信息。

    【讨论】:

      猜你喜欢
      • 2017-05-02
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      相关资源
      最近更新 更多