我想用映射函数动态重命名键。为此,我做了这个:
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}
转换此函数的返回值时,一切正常,但没有强制转换,它不会编译。
错误讯息:
TS2322: Type '{ [x: string]: string; }' is not assignable to type '{ [P in K]: string; }'.
从我看到的DateRange
接口的两个键都被使用,因此返回值的键应该都是K
类型。
该函数必须如何,不需要强制转换?
示例电话:
const formatted = format(
{startDate: 'startDateValue', endDate: 'endDateValue'},
{startDate: 'start', endDate: 'end'}
);
// formatted = {end: 'endDateValue', start: 'startDateValue'}
答案 0 :(得分:1)
我可以重现你的问题,而且在GitHub问题之前似乎已经noted了。这个问题已被标记为“已修复”,但这一部分显然没有。无论如何,这可能只是一个设计限制... TypeScript可以用一个通用类型参数表示一个对象的唯一方法就是使用mapped type,我怀疑TypeScript中的任何内容都会将对象文字解释为自动映射的类型。我不知道GitHub中是否存在更合适的现有问题,或者有人应该打开一个问题。
目前,您必须处理变通方法。你使用的那个很好(断言返回值的类型),如果你小心的话。 稍微更类型安全的是逐个添加属性,如:
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;
}
如果遗漏一个属性,它仍然不会抱怨,但它会阻止你添加随机的其他字符串值计算属性:
const badProp: string = "uh oh"
return {
[mapping.startDate]: range.startDate,
[mapping.endDate]: range.endDate,
[badProp]: "whoops" // no error
} as { [P in K]: string };
VS
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)
但是,对你来说这可能不值得,你的类型断言是合理的。希望这很有帮助。祝你好运!