typescript - 对象重映射器的高级类型
问题描述
我正在尝试创建一个函数,让调用者重新映射给定特定映射的对象。结果对象应该能够知道新的新字段名称和类型。
这在打字稿中可能吗?我认为此时我需要的只是返回类型。这是我拥有的非工作代码:
const mapping = {
a: "learn",
b: "state"
}
const original = {
a: false,
b: 0
}
const map = <
Mapping,
Original
>(
mapping: Mapping,
states: Original
): {
[key: Mapping[key]]: Original[key] //WHAT IS THE CORRECT TYPE HERE?
} => {
return Object.keys(original).reduce((total, key) => {
return {
...total,
[mapping[key]]: original[key] //THERE IS AN ERROR HERE TOO BUT I AM NOT WORRIED ABOUT THAT RIGHT NOW
}
}, {})
}
const remapped = map(mapping, original)
console.log(remapped)
console.log(remapped.learn)
console.log(remapped.state)
我本质上是在尝试重命名a
为learn
和。代码正常工作,但我收到类型错误('key' 指的是一个值,但在这里被用作一种类型。)。任何帮助将不胜感激!b
state
解决方案
首先,您的工具箱中需要@jcalz 令人惊叹的UnionToIntersection
实用程序类型。
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never;
现在让我们创建自己的实用程序类型:
1 type Remap<A extends { [k: string]: string }, B> =
2 keyof B extends keyof A ?
3 { [P in keyof B & keyof A]: { [k in A[P]]: B[P] } } extends
4 { [s: string]: infer V } ?
5 UnionToIntersection<V>
6 : never
7 : never;
解释:
- ln:1,将 A 的值约束为字符串。
- ln:2,约束所有 B 的键都存在于 A
- ln:3,映射到
{ "a": {"learn": boolean}, "b": {"state": number} }
- ln:4,取值部分,变为:
{"learn": boolean} | {"state": number}
union - ln:5,
UnionToIntersection
施展魔法!
把东西放在一起:
const mapping = {
a: "learn",
b: "state",
} as const; // mark as `const` is necessary to infer value as string literal
// else it'll just be string
const original = {
a: false,
b: 0,
};
const map = <
M extends { [k: string]: string },
O extends { [k: string]: any }
>(mapping: M, original: O): Remap<M, O> => {
return Object.keys(original).reduce((total, key) => {
return {
...total,
[mapping[key]]: original[key]
}
}, {} as any); // as any to mute error
};
我遇到了 jcalz 的另一个答案,它提供了比我更优雅的解决方案。检查该答案以获得解释。我将在此处附加它:
type Remap2<
M extends { [k: string]: string },
O extends { [P in keyof M]: any }
> = {
[P in M[keyof M]]: O[
{ [K in keyof M]: M[K] extends P ? K : never }[keyof M]
]
};
推荐阅读
- git - pip install_requires 从 git 存储库克隆,但缺少存储库内容
- r - as.Date 不会出错
- amazon-web-services - Aurora 无服务器冷却时间缩减
- c# - 如何创建 gRPC ContextPropagationToken
- java - 为什么我执行请求时出现 NullPointerException?
- ag-grid - 上下文菜单需要时间来加载,并且没有显示加载详细信息的选项
- python - 如何在 Kivy 屏幕小部件中初始化实例
- php - 如何通过单击按钮从数据库中获取数据到相应的邮件?
- reactjs - 减速器在 IonRouterOutlet 内无法正常工作
- ruby-on-rails - 在 Rails 中的模式上检查远程真