node.js - 如何将承诺响应映射到节点打字稿中的对象?
问题描述
我有来自 3rd 方图书馆的回复
{
"public_id": "123456",
"Name": "John"
}
我需要映射到
{
"Id": "123456",
"FirstName": "John"
}
我需要有两个模型来做到这一点吗?还是我有一个注释可以自动映射节点打字稿中的属性?请告诉我。谢谢
解决方案
这不会自动发生。如果要将对象的键映射到不同的键集,则需要在运行时以某种形式完成该工作。一种方法是创建一个映射键的辅助函数,将其放入库中,并根据需要使用它。
这是一种可能的实现,假设您使用的是 TypeScript 4.1 并且拥有 ES2019+ 运行时:
const keyMapper =
<M extends Record<keyof M, K>, K extends PropertyKey>(map: M) =>
<T extends object>(obj: T): { [K in keyof T as K extends keyof M ? M[K] : K]: T[K] } =>
Object.fromEntries(Object.entries(obj).
map(([k, v]) => [k in map ? map[k as keyof M] : k, v])
) as any;
在我试图解释之前,让我们看看它的实际效果。我们可以使用keyMapper()
创建一个新函数,专门用于将您的 api 响应与public_id
和Name
键转换为您所需的值类型,并使用Id
和FirstName
键:
const mapApiVal = keyMapper({ public_id: "Id", Name: "FirstName" });
mapApiVal
函数也是如此。如果我们有这样的 api 响应:
const apiVal = {
"public_id": "123456",
"Name": "John"
}
我们可以将其转换为所需的形式:
const mapped = mapApiVal(apiVal);
/* const mapped: {
Id: string;
FirstName: string;
} */
console.log(mapped); // { "Id": "123456", "FirstName": "John" }
console.log(mapped.Id.repeat(2)); //123456123456
console.log(mapped.FirstName.toUpperCase()); // JOHN
所以它有效,耶!
那么它是怎样工作的?它有两个部分:打字和实现。打字只是调用签名:
/* const keyMapper: <M extends Record<keyof M, K>, K extends PropertyKey>(
map: M) => <T extends object>(obj: T) =>
{ [K in keyof T as K extends keyof M ? M[K] : K]: T[K]; } */
它说这keyMapper
是一个通用函数,它接受map
一个对象类型的参数,M
其键是任何东西,并且其属性本身是类键(string
或number
或symbol
)......它返回一个函数。它返回的函数也是通用的,接受obj
一个对象类型的参数T
,并返回一个值。它返回的值是具有重新映射键的映射类型(如 TypeScript 4.1 中所介绍的)。它说:对于's typeK
中的每个键,我们检查它是否是 的键之一。如果是这样,我们替换为(at key的值)。如果没有,我们离开obj
T
M
K
M[K]
M
K
K
独自的。T[K]
我们独自离开这处房产。
现在进行实施。它看起来像这样(删除了类型信息):
map => obj => Object.fromEntries(Object.entries(obj).
map(([k, v]) => [k in map ? map[k] : k, v])
);
在这里,我们使用Object.entries()
to 转换obj
为键值对数组,处理这些对,然后使用Object.fromEntries()
to 将其转回对象。处理与上面的键重映射键入非常相似:对于每个键k
,我们检查它是否是 的键map
。如果是,我们将其替换为map[k]
,否则我们将其保留为k
。并且价值v
被单独留下。
不幸的是,编译器不够复杂,无法验证实现是否满足类型。为了防止编译器警告并让编译器接受实现,我不得不使用一些类型断言:as keyof M
和as any
. 这意味着我有责任为自己实现类型安全,无论好坏。
推荐阅读
- python - 尝试在python中创建Circle类,现在几乎成功了,唯一剩下的问题是如何在历史列表中保留以前的半径而不是替换它
- python - FASTAPI 自定义中间件在内部获取请求主体
- sql - 内部连接语法错误,但现在确定错误是什么
- mysql - 如何从 MySQL 中的两个不同表中减去列中的值?
- python - 如何解决混淆 TypeError 和 Pickle
- makefile - 如何在 Makefile 中取消定义变量
- python - 如何在函数式编程中定义一个函数?
- azure - 将 Windows Azure 应用服务恢复到原始/默认状态
- machine-learning - 调整 SVR 的超参数
- airflow - 在气流中的 DAG 之间共享信息