问题描述
限时送ChatGPT账号..我想使用映射函数动态重命名键.为此,我做了这个:
I want to dynamically rename keys with a mapping function. For this, I've made this:
interface DateRange {
startDate: string;
endDate: string;
}
function format<K extends string>(range: DateRange, mapping: {[X in keyof DateRange]: K}): {[P in K]: string} {
return {
[mapping.startDate]: range.startDate,
[mapping.endDate]: range.endDate,
};
}
当我用 as {[P in K]: string}
转换这个函数的返回值时,一切正常,但没有转换,它不会编译.
When I cast the return value of this function with as {[P in K]: string}
it all works fine, but without the cast it doesn't compile.
错误信息:
TS2322: Type '{ [x: string]: string; }' is not assignable to type '{ [P in K]: string; }'.
从我看到的 DateRange
接口的两个键都使用了,所以返回值的键应该都是 K
类型.
From what I see both keys of the DateRange
interface are used, so the keys of the return value should all be of type K
.
函数应该是什么样子的,不需要强制转换?
How must the function look like, that a cast is not needed?
示例调用:
const formatted = format(
{startDate: 'startDateValue', endDate: 'endDateValue'},
{startDate: 'start', endDate: 'end'}
);
// formatted = {end: 'endDateValue', start: 'startDateValue'}
推荐答案
我可以重现你的问题,而且好像已经之前在 GitHub 问题中提到.该问题已被标记为已修复",但这部分显然没有.无论如何,这可能只是一个设计限制...... TypeScript 可以将具有泛型类型参数的对象表示为键的唯一方法是使用 映射类型,我怀疑 TypeScript 中的任何内容都会自动将对象文字解释为映射类型.不知道 GitHub 有没有更合适的现有 issue 或者是否有人应该打开一个.
I can reproduce your problem, and it seems to have been noted before in a GitHub issue. That issue has been marked "fixed", but this part of it obviously has not. Anyway, this might just be a design limitation... the only way TypeScript could represent an object with a generic type parameter as a key is with a mapped type, and I doubt that anything in TypeScript will interpret an object literal as a mapped type automatically. I don't know if there's a more appropriate existing issue in GitHub or if someone should open one.
现在,您必须处理变通方法.如果您小心的话,您使用的那个很好(断言返回值的类型).一个稍微类型安全的方法是一个一个地添加属性,如:
For now, you have to deal with workarounds. The one you used is fine (assert the type of the return value), if you're careful. A slightly more type-safe one is to add properties one by one, as in:
function format<K extends string>(
range: DateRange,
mapping: { [X in keyof DateRange]: K }
): { [P in K]: string } {
const ret = {} as { [P in K]: string }; // assertion
ret[mapping.startDate] = range.startDate; // safer
ret[mapping.endDate] = range.endDate; // safer
return ret;
}
如果你遗漏了一个属性,它仍然不会抱怨,但它会阻止你添加其他随机的字符串值计算属性:
It still won't complain if you leave out a property, but it will stop you from adding random other string-valued computed properties:
const badProp: string = "uh oh"
return {
[mapping.startDate]: range.startDate,
[mapping.endDate]: range.endDate,
[badProp]: "whoops" // no error
} as { [P in K]: string };
对比
const badProp: string = "uh oh"
const ret = {} as { [P in K]: string };
ret[mapping.startDate] = range.startDate;
ret[mapping.endDate] = range.endDate;
ret[badProp] = "whoops"; // error (implicit any)
不过,这对您来说可能不值得,而且您的类型断言是合理的.希望这有帮助.祝你好运!
That might not be worth it to you, though, and your type assertion is reasonable. Hope that's helpful. Good luck!
这篇关于重命名对象/接口类型安全的键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论