【发布时间】:2018-12-13 01:04:18
【问题描述】:
考虑以下函数:
function keysToValuesClone<TObject extends {}>(keysAndValuesObj: TObject) {
const clone = Object.assign({}, keysAndValuesObj);
Object.keys(clone).forEach(key => clone[key] = key);
const frozen = Object.freeze(clone);
return (<any>frozen) as Readonly<{ // The `any` is regrettable... see below
[K in keyof typeof clone]: K
}>;
}
我可以为这个函数提供一个像这样的对象字面量:
const myHeaders = keysToValuesClone({
'a property with spaces': '',
'and another': '',
});
而产生的myHeaders将有这种类型:
Readonly<{
'a property with spaces': "a property with spaces";
'and another': "and another";
}>
我喜欢这个函数的实用性,但写它在我脑海中提出了两个问题:
是否有可能丢失any?
如果我将keysToValuesClone 的最后一行更改为:
return frozen as Readonly<{
[K in keyof typeof clone]: K
}>;
然后我遇到以下错误:
Type 'Readonly<TObject & {}>' cannot be converted to type 'Readonly<{ [K in keyof (TObject & {})]: K; }>'.
Type '(TObject & {})[P]' is not comparable to type 'P'.
我已经尝试以多种不同的方式说服编译器在没有any 类型断言的情况下允许此函数,但所有尝试都失败了。这可以改进吗?你能说服编译器在不求助于any 的情况下顺其自然吗?
是否可以创建一个类似的函数来从 string[] 构造此类型?
我很想写这段代码:
const myHeaders = keysToValuesUsingArray([
'a property with spaces',
'and another'
]);
即提供一个字符串数组并使其输出与上述相同。 Codewise 我可以这样实现:
function keysToValuesArray(keys: string[]) {
const obj = keys.reduce((objInTheMaking, key) => ({ [key]: key, ...objInTheMaking }), {});
return obj;
}
但这会产生{} 类型。有没有办法在类型系统中提示这里发生了什么?
我玩过keyof / typeof / Tuple 等都无济于事。所以我的朋友们,我求助于你。
教育我。
感谢提香!
太棒了提香;非常感谢!我最终通过 Readonly 调整推出了您的阵列解决方案;见下文:(我现在莫名其妙地爱上了Object.freeze;这是我的果酱)
function keysToValuesArray<T extends string>(keys: T[]): Readonly<{ [P in T] : P}> {
const obj = keys.reduce((objInTheMaking, key) => ({ [key]: key, ...objInTheMaking }), {} );
const frozen = Object.freeze(obj);
return frozen as Readonly<{ [P in T] : P}>;
}
再次感谢!
【问题讨论】:
标签: typescript types