The following function workOnFunctions takes an object and an array of keys to that object where all the keys map to a function:
const myObj = {
a: () => 1,
b: "test",
c: 2,
d: (a : number) => a*2
}
function workOnFunctions <K extends PropertyKey>(o: Record<K, Function>, names: K[]) {
names.forEach(name => {
const f = o[name]; // do something with function f
})
}
I noticed that it works as intended when I do this:
workOnFunctions(myObj, ["a", "d"]); // works
But when storing the array in a variable and then passing this variable to the function, I get the error
Argument of type '{ a: () => number; b: string; c: number; d: (a: number) => number; }' is not assignable to parameter of type 'Record<string, Function>'.
Property 'b' is incompatible with index signature.
Type 'string' is not assignable to type 'Function'.
Code:
const names = ["a", "d"];
workOnFunctions(myObj, names);
Why is that the case? It seems like the compiler can't infer the type of names correctly. When I pass the array directly, it can. I also tried this:
const names = ["a", "d"] as const;
workOnFunctions(myObj, names);
Which does not work either.
My final goal is to write a function that takes an object and an array of keys that point to functions within that object.
EDIT: Partial solution found, but I don't understand why
Looks like this works:
type KeysMatching<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T]
const names : Array<KeysMatching<typeof myObj, Function>> = ["a", "d"];
workOnFunctions(myObj, names);
I got KeysMatching from here: TypeScript: Accept all Object keys that map to a specific type
But why can the compiler infer this complex type by itself when I directly pass the array? Is there a trick to auto-infer the type also when using a separate array?