你最想使用
key remapping in mapped types
你的
renameProperties()
函数应该是
generic
在里面
T
,输入的类型,以及
M
,键映射的类型。然后对于每个键
K
在里面
keyof T
,您使用键创建属性
M[K]
:
declare function renameProperties<
T extends object,
const M extends Record<keyof T, PropertyKey>
>(input: T, mapping: M):
{ [K in keyof T as M[K]]: T[K] }
在这里你可以看到
M
已经
constrained
与具有相同密钥的东西
T
并且其属性本身都是类似密钥的(
PropertyKey
).
这给了你一切技术上需要的工作。
唯一的问题是,如果将映射对象写为
object literal
对于映射,TypeScript默认情况下不会跟踪
literal types
的属性值。如果你写
{a: "x", b: "y"}
,TypeScript将推断为
{a: string, b: string}
,这对你没有帮助。你会想要一个
const
assertion
如在
{a: "x", b: "y"} as const
相反
一个改进是
M
a
const
type parameter
,以便如果映射参数是对象文字,则TypeScript将其视为
const
断言存在,因此调用者可以忽略它:
const input = { a: 1, b: "hello" };
const result = renameProperties(input, { a: "alpha", b: "beta" });
// ^? const result: { alpha: number; beta: string; }
因此,这符合要求。请注意,如果映射为
不
内联传递,那么您需要
const
断言。没有什么能神奇地让它为你工作:
const mapping = { a: "x", b: "y" };
// ^? const mapping: {a: string, b: string}
const r2 = renameProperties(input, mapping);
// ^? const r2: { [k: string]: string | number }
所以你会想要
const mapping = { a: "x", b: "y" } as const;
const r2 = renameProperties(input, mapping);
// ^? const r2: { x: number; y: string }
Playground link to code