I am working with this function which rebuilds the initial object, but casting every values to BigNumbers recursively.
export const castObjectValuesToBigNumber = function(initialObj: StringMap, nestedProp?: string) {
let _castedObj: StringMap = {};
for(const [property, value] of Object.entries(initialObj)) {
if(typeof(value) === "object" && !(value instanceof BN)) {
const newVal = castObjectValuesToBigNumber(value, property);
_castedObj = { ..._castedObj, ...newVal };
} else {
if(nestedProp) {
if(!_castedObj[nestedProp]) _castedObj[nestedProp] = {};
_castedObj[nestedProp][property] = BigNumber.from(value.toString());
} else {
_castedObj[property] = BigNumber.from(value.toString());
}
}
}
return _castedObj;
}
I would like to make it so that the return type is same as the initialObj
type but with end values as BigNumber type.
Example:
const myValue = {
propertyA: new BN(105),
propertyB: {
propertyC: new BN(1),
propertyD: new BN(2),
propertyE: new BN(3)
},
propertyF: {
propertyG: new BN(4)
}
}
I would like that if I put this value as a parameter of my function, typescript automatically returns this type:
{
propertyA: BigNumber,
propertyB: {
propertyC: BigNumber,
propertyD: BigNumber,
propertyE: BigNumber
},
propertyF: {
propertyG: BigNumber
}
}
I tried lots of things with generics types and nested types but I always have an error of some type.
Here is a Minimum Reproducible Example:
/////////////////////
/// DECLARATIONS
interface StringMap { [key: string]: any }
class BN {
value;
constructor(num: number | string) {
this.value = num;
}
_isBN() {
return true;
}
}
class BigNumber {
value;
constructor(num: number | string) {
this.value = num;
}
_isBigNumber() {
return true;
}
}
const myValue = {
propertyA: new BN(105),
propertyB: {
propertyC: new BN(1),
propertyD: new BN(2),
propertyE: new BN(3)
},
propertyF: {
propertyG: new BN(4)
}
};
/////////////////////
/// FUNCTION
export const castObjectValuesToBigNumber = function(initialObj: StringMap, nestedProp?: string) {
let _castedObj: StringMap = {};
for(const [property, value] of Object.entries(initialObj)) {
if(typeof(value) === "object" && !(value instanceof BN)) {
const newVal = castObjectValuesToBigNumber(value, property);
_castedObj = { ..._castedObj, ...newVal };
} else {
if(nestedProp) {
if(!_castedObj[nestedProp]) _castedObj[nestedProp] = {};
_castedObj[nestedProp][property] = new BigNumber(value.toString());
} else {
_castedObj[property] = new BigNumber(value.toString());
}
}
}
return _castedObj;
}
/////////////////////
/// TEST
/*
Result is of type StringMap while I would like it to be :
{
propertyA: BigNumber,
propertyB: {
propertyC: BigNumber,
propertyD: BigNumber,
propertyE: BigNumber
},
propertyF: {
propertyG: BigNumber
}
}
*/
const myCastedValue = castObjectValuesToBigNumber(myValue);
CodePudding user response:
The type we'll use to recursively change each BN
to BigNumber
could look like this:
type CastToBigNumber<T> = T extends BN ? BigNumber : {
[K in keyof T]: CastToBigNumber<T[K]>
};
If T
is a BN
, then we change it to BigNumber
, otherwise it's an object and we change all its properties.
The function definition now looks like this, using a generic parameter:
export const castObjectValuesToBigNumber = function<Initial extends StringMap>(initialObj: Initial, nestedProp?: string): CastToBigNumber<Initial> {