优化 JSON 到 Typescript 映射
Posted
技术标签:
【中文标题】优化 JSON 到 Typescript 映射【英文标题】:Optimise JSON to Typescript Map 【发布时间】: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');
这将返回对象,但 bar
和 mapOfBar
是对象类型,而不是 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;
)
);
这会将bar
和mapOfBar
作为地图返回给我,这很棒。
称我为完美主义者,但不知何故这让人觉得笨拙和错误:
map((res: Foo) =>
行表明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"
【问题讨论】:
【参考方案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 了解更多信息。
【讨论】:
以上是关于优化 JSON 到 Typescript 映射的主要内容,如果未能解决你的问题,请参考以下文章
如何在 TypeScript Angular 2 中将 Json 对象数组映射到另一个普通 json 对象
如何在 Angular 2 的 TypeScript 中映射嵌套的 Json