Edit
requestedFunctionAlias
is dynamic.
For instance,
const getFn = ({ requestedFunctionAlias }) => {
return FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias]];
}
const fn = getFn({ requestedFunctionAlias: 'a1' });
fn({ age: 30 })
Suppose the following,
const myFunction1 = ({ name }: { name: string }) => console.log('name', name);
const myFunction2 = ({ age }: { age: number }) => console.log('age', age);
const myFunction3 = ({ hobbies }: { hobbies: string[] }) => console.log('hobbies', hobbies);
const FUNCTION_ALIASES = {
a1: 'myFunction1',
a2: 'myFunction2',
a3: 'myFunction3',
};
const FUNCTIONS_MAP = {
myFunction1: 'a1',
myFunction2: 'a2',
myFunction3: 'a3',
};
const FUNCTIONS_MATRIX = {
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction1]]: myFunction1,
// ^^^ Element implicitly has an 'any' type
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction2]]: myFunction2,
// ^^^ Element implicitly has an 'any' type
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction3]]: myFunction3,
// ^^^ Element implicitly has an 'any' type
};
const requestedFunctionAlias: string = 'a1';
const fn = FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias]];
// ^^^^ Element implicitly has an 'any' type
fn({ name: 'Michael!' });
// ^^^^^^ Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }'
I can solve some of these errors like this,
const FUNCTIONS_MATRIX = {
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction1 as keyof typeof FUNCTION_ALIASES]]: myFunction1,
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction2 as keyof typeof FUNCTION_ALIASES]]: myFunction2,
[FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction3 as keyof typeof FUNCTION_ALIASES]]: myFunction3,
};
const fn = FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias as keyof typeof FUNCTION_ALIASES]];
But this seems messy and it still doesn't solve the error at fn({ name: 'Michael!' });
.
What can I do here?
CodePudding user response:
First declare FUNCTION_ALIASES
and FUNCTIONS_MAP
as const
. With this you tell typescript that their type is narrower than key: string
.
const FUNCTION_ALIASES = {
a1: "myFunction1",
a2: "myFunction2",
a3: "myFunction3",
} as const;
const FUNCTIONS_MAP = {
myFunction1: "a1",
myFunction2: "a2",
myFunction3: "a3",
} as const;
Then remove type declaration string
from requestedFunctionAlias
, since it loses type information - it's type is literal "a1"
and typescript needs it, to know at type checking time exactly which function will be returned:
const requestedFunctionAlias = "a1";
Edit: With function overloading you can kinda handle dynamic argument:
const myFunction1 = ({ name }: { name: string }) => console.log("name", name);
const myFunction2 = ({ age }: { age: number }) => console.log("age", age);
const myFunction3 = ({ hobbies }: { hobbies: string[] }) =>
console.log("hobbies", hobbies);
function myFunction(which: "a1", arg: Parameters<typeof myFunction1>[0]): void;
function myFunction(which: "a2", arg: Parameters<typeof myFunction2>[0]): void;
function myFunction(which: "a3", arg: Parameters<typeof myFunction3>[0]): void;
function myFunction(
which: "a1" | "a2" | "a3",
arg: any
) {
switch (which) {
case "a1":
return myFunction1(arg);
case "a2":
return myFunction2(arg);
case "a3":
return myFunction3(arg);
default:
break;
}
}
myFunction("a1", { name: "Michael!" });