我正在尝试实现这样的目标:
const input = {a: 1, b: "hello"};
const result = renameProperties(input,{a: "alpha", b: "beta"});
result.alpha // number
result.beta // string
result.foo //Property 'foo' does not exist on type...
所以我的转换函数如下所示:
export function renameProperties<
TInput extends Record<string, unknown>,
TConversionMap extends Record<keyof TInput, string>,
TOutput extends // heres where I get stuck
>(input: TInput, conversionMap: TConversionMap): TOutput {
}
作为第一步我已经得到:
TOutput extends {[K in TConversionMap[keyof TInput]] : string}
这不完全符合我的要求——我希望结果只包含转换后的键。
result.alpha // string
result.beta // string
result.foo //string - but really was hoping to see an error here
第二部分将涉及保留输入的价值,我正在考虑类似的事情:
TOutput extends {[K in TConversionMap[keyof TInput]] : TInput[The Input key, if we can retain a reference to it]}
我该怎么做?这可能吗?
您最想在映射类型中使用键重映射。您的
renameProperties()
函数应该是通用的,T
输入的类型,以及M
键映射的类型。然后对于K
中的每个键keyof T
,您使用键创建一个属性M[K]
:在这里您可以看到已经
M
被约束为具有与 相同的键的某个东西,T
并且其属性都是类似键本身的(PropertyKey
)。这为您提供了实现此功能所需的所有技术信息。
唯一的问题是,如果你将映射对象写为映射的对象文字,TypeScript 将默认不会跟踪属性值的文字类型
{a: "x", b: "y"}
。如果你写,TypeScript 会将其推断为{a: string, b: string}
,这对你没有帮助。你应该使用这样的const
断言{a: "x", b: "y"} as const
。一个改进是制作
M
一个const
类型参数,这样如果映射参数是一个对象文字,TypeScript 就会将其视为断言const
存在,因此调用者可以将其省略:这样就可以按预期工作了。请注意,如果映射不是内联传递的,则需要该
const
断言。没有什么可以神奇地为您实现这一点:所以你会想要
游乐场链接到代码