Edit
I got a step further. The more complex example looks like this (Playground):
type DeepFunctions = {
[key: string]: ((...args: any[]) => any) | DeepFunctions
}
function changeDeepFunctions<T extends DeepFunctions>(deepFunctions: T): T {
const copy = {...deepFunctions} as DeepFunctions;
for(let key in copy) {
const value = deepFunctions[key];
if(value instanceof Function) {
copy[key] = ((...args) => {
console.log("hi");
return value(...args);
});
} else {
copy[key] = changeDeepFunctions(value);
}
}
return copy as T;
}
Everythings fine and the output is exactly like it should be. However, I don't get why I needed to do it this way. Maybe still someone can help me understand.
Original Post
I'm kind of new to typescript and I cannot find a good solution for a seemingly easy problem.
All Code you can see here is written down in this PlayGround.
Because my real example is a bit too heavy, I reduced it to these (hopefully :)) equal examples:
- I would like to write a function that gets an object with several functions and map it to an object with mapped functions. Kind of hard to describe, but easy to understand with code:
type Functions = {
[key: string]: (...args: any[]) => any;
};
export function changeFunctions<T extends Functions>(functions: T): T {
const copy = { ...functions };
for (let key in functions) {
const func = functions[key];
copy[key] = ((...args) => {
console.log("hi");
return func(...args);
});
}
return copy;
}
If you have look at the code in the playground, you can see the
copy[key] = ...
line produces a type error: Type '(...args: any[]) => any' is not assignable to type 'T[Extract<keyof T, string>]'.(2322) It's fixable by adding as typeof func at the end of the assignment, but that doesn't feel right.
Is there a clean way to write this?
The second example extends the first, so the solution might be similar:
- As an extension to 1., the function now should be able to correctly convert objects containing functions, but also recursively contain other objects with functions. Here is the code:
type DeepFunctions = {
[key: string]: ((...args: any[]) => any) | DeepFunctions
}
function changeDeepFunctions<T extends DeepFunctions>(deepFunctions: T): T {
const copy = {...deepFunctions};
for(let key in deepFunctions) {
const value = deepFunctions[key];
if(value instanceof Function) {
copy[key] = ((...args) => {
console.log("hi");
return value(...args);
});
} else {
// it must be a DeepFunctions object
copy[key] = changeDeepFunctions(value);
}
}
return copy;
}
As you can see in the playground, the copy[key] assignment fails in the same way as in the example above. The other assignment:
copy[key] = changeDeepFunctions(value);
doesn't raise an error. The type is still wrong, though. Hovering over value shows a type of never.
Have you any hints how to correctly write such methods in typescript with correct types?