transformer
requires a key k
of type K
(the generic type parameter), yet Object.keys
only returns broad strings and causes a compilation error.
For potential solutions, refer to this response; using a type assertion is appropriate in this scenario.
Furthermore, an issue arises with the inference of type parameter TObj
for the transformer
within the outer function. This can be resolved by currying the inner function with the actual obj: TObj
. Avoiding the use of any
types is strongly encouraged to ensure better typing enforcement.
To address these concerns, we can redefine the typings based on the callback function of transformer
within the makeTransform
function. By making TObj
a type parameter of the inner function that meets the constraints of the outer transformer
, we eliminate any unnecessary type assertions and usage of any
.
function makeTransform<
T extends Record<string, (arg: any) => any>
>(transformer: T) {
return <TObj extends { [P in keyof T]: Parameters<T[P]>[0] }>(obj: TObj) => {
const objClone: Omit<TObj, keyof T> = { ...obj };
// Type casting is necessary here to maintain correct typings
const mapped = {} as { [P in keyof T]: ReturnType<T[P]> };
for (const k of Object.keys(transformer)) {
// Using a workaround for Object.keys typings
const kC = k as keyof T;
mapped[kC] = transformer[kC](obj[kC]);
}
return { ...objClone, ...mapped };
};
}
Test it out:
const trans = makeTransform({
a: (x: number) => String(x * 2),
b: (x: string) => parseInt(x)
});
const res0 = [{ a: 1, b: "11" }, { a: 2, b: "22" }].map(trans);
const res1 = [{ a: 1, b: "11", c: new Date() }, { a: 2, b: "22", c: {} }].map(trans);
const res2 = [{ a: 1 }, { a: 2, b: "22" }].map(trans); // error: b not found (OK)
const res3 = [{ a: 1, b: "11" }, { b: "22" }].map(trans); // error: a not found (OK)
const res4 = [{ a: "1", b: "11" }, { a: 2, b: "22" }].map(trans); // error: 'a' incompatible (OK)
const res5 = [{ a: 1, b: "11" }, { a: 2, b: 22 }].map(trans); // error: 'b' incompatible (OK)
console.log(res0); // [{ a: "2", b: 11 }, { a:"4", b: 22 }]
Playground