我想编写一个函数,使我可以将所有对象属性(我只有纯对象)转换为特定类型。目前,我只想强制转换为基元boolean
,string
和number
。遵循以下原则:
function castMembers<TObject extends object, TValue extends boolean | string | number>(instance: TObject, type: TValue): Record<keyof TObject, TValue> {
Object.keys(instance).reduce((result, k) => {
// ERROR
result[k] = new type(instance[k]).valueOf();
return result;
}, {});
}
将来,只要满足我的接口定义(它必须包含valueOf
函数),我可以将其类型扩展到任何类型。所以...
我很清楚,我不能真正基于泛型类型实例化新对象,因为它们仅用于编译时。这就是为什么我添加了第二个参数,以便可以提供用于铸造的构造函数的原因。但是我遇到错误,或者我无效地写了我的TValue
通用参数或第二个参数的类型。
如何编写这样的功能?
我尝试引入构造函数接口,这使我非常接近,但仍然出现错误:
interface IConstructor<TValue> {
new(value?: any): TValue;
}
function castMembers<TObject extends object, TValue extends number | string | boolean>(instance: TObject, toType: IConstructor<TValue>): Record<keyof TObject, TValue> | never {
return (Object.keys(instance) as (keyof TObject)[]).reduce((result, key) => {
result[key] = new toType(instance[key]).valueOf() as TValue;
return result;
}, {} as Record<keyof TObject, TValue>);
}
答案 0 :(得分:1)
实际上,我在玩游戏时自己解决了它。我终于做到了。
这是代码。
interface IPrimitiveLike<T> {
valueOf(): T;
}
interface IConstructor<T> {
readonly prototype: IPrimitiveLike<T>;
new(value?: any): IPrimitiveLike<T>;
}
export default function castMembers<TObject extends object, TValue extends IPrimitiveLike<unknown>>(instance: TObject, toType: IConstructor<TValue>): Record<keyof TObject, TValue> | never {
return (Object.keys(instance) as (keyof TObject)[]).reduce((result, key) => {
result[key] = new toType(instance[key]).valueOf() as TValue;
return result;
}, {} as Record<keyof TObject, TValue>);
}
此代码将正确执行:
let obj = {
text: 'test',
value: 123,
negative: 0,
bool: true
};
castMembers(obj, Boolean); // { text: true, value: true, negative: false, bool: true }
castMembers(obj, String); // { text: 'test', value: '123', negative: '0', bool: 'true' }
castMembers(obj, Custom); // also works if your custom class defines a valueOf() function
我唯一不完全确定的是使用unknown
类型。当然可以用any
代替它,但理想情况下,它应该是与valueOf
返回类型相关的原始类型。