I want to write a function that converts a specific value in an object from string to a number.
Here is my function:
export function convertStringToNumber<K extends string>(
obj: Record<K, object>,
val: string
): Record<K, number> {
const result: Partial<Record<K, unknown>> = {}
for (const key in obj) {
if (key === val) {
result[key] = Number(obj[key])
} else {
result[key] = obj[key]
}
}
return result as Record<K, number>
}
My function is working, but my TypeScript is complaining about the types. Can TypeScript take the input types and just change the type of an appropriate key to a number?
I have a second version, perhaps this one is more appropriate:
export function convertStringToNumber2<T> (
obj: T,
val: string
): T {
const result: Partial<T> = {}
for (const key in obj) {
if (key === val) {
result[key] = Number(obj[key])
} else {
result[key] = obj[key]
}
}
return result
}
TypeScript is complaining: Type 'number' is not assignable to type 'T[Extract<keyof T, string>]'.ts(2322)
CodePudding user response:
By using two generics, you can derive a return type from your inputs with the help of the utility types Omit<Type, Keys>
and Record<Keys, Type>
, like this:
function convertStringToNumber <
O extends Record<string, unknown>,
K extends keyof O
>(obj: O, key: K): Omit<O, K> & Record<K, number> {
return {...obj, [key]: Number(obj[key])};
}
const input = {
a: "1",
b: "2",
c: "x",
};
const output1 = convertStringToNumber(input, "a");
console.log(output1); // { a: 1, b: "2", c: "x" }
const output2 = convertStringToNumber(input, "c");
console.log(output2); // { a: "1", b: "2", c: NaN }
Compiled JS from the TS Playground:
"use strict";
function convertStringToNumber(obj, key) {
return { ...obj, [key]: Number(obj[key]) };
}
const input = {
a: "1",
b: "2",
c: "x",
};
const output1 = convertStringToNumber(input, "a");
console.log(output1); // { a: 1, b: "2", c: "x" }
const output2 = convertStringToNumber(input, "c");
console.log(output2); // { a: "1", b: "2", c: NaN