[英]Typescript dynamic function by key/value of object
有没有办法基于初始接口设置 function? 我有一堆 listOfFunctions 和等量的包含函数类型的接口。 我想创建一个返回自定义钩子的工厂。 这个想法是节省大量代码,并使编辑和添加功能到所有钩子变得轻而易举。
FunctionInterface
是所有 function 名称及其返回值。
listOfFunctions
是一个设置 function (实际代码有一个配置),它返回一个带有函数列表的 object。
theChosenFunction
是一个 function 将在允许我与 listOfFunction 函数之一交互的钩子中返回。 这意味着参数(如果需要)。 实际应用程序中的函数是 Promises,它将设置钩子的 state。 在这个例子中,我只返回一个值和 setState。
A)这可能与funcObject[funcName]()
并创建一个 function 以使用 typescript 调用吗? 这将需要添加或不添加参数的能力。
B) 有没有办法获取 function 类型的返回值? 所以在这个例子中: type CanThisWork = () => string;
我想提取string
; 这个想法不是对所有 listOfFunctions 和 FunctionInterfaces 进行重构。 他们有很多。 如果我必须创建一个复杂的工厂,那么我发现这更经济。
interface FunctionInterface {
noParamsNoReturn: () => void;
noParamsNumberReturn: () => number;
propsAndNoReturn: (id: string) => void;
propsAndReturn: (id: string) => string;
}
const listOfFunctions = (): FunctionInterface => {
return {
noParamsNoReturn: () => void,
noParamsNumberReturn: () => 1,
propsAndNoReturn: (id: string) => console.log(id),
propsAndReturn: (id: string) => id,
}
}
function runThis<T>(funcName: keyof T, funcObject: T): void {
const [value, setValue] = React.useState();
// Can I have typescript set up the params here?
const theChosenFunction = ();
const theChosenFunction = (props) => {
// Can I have typescript invoke the function properly here?
const result = funcObject[funcName](); // funcObject[funcName](props)
if (result) {
setValue(result);
}
}
return {
theChosenFunction
}
}
const result = runThis<FunctionInterface>('noParamsNoReturn', listOfFunctions());
result.theChosenFunction()
// OR
result.theChosenFunction('someId');
有内置的Parameters<T>
和ReturnType<T>
实用程序类型,它们采用 function 类型T
并使用条件类型推断来分别提取参数元组和返回类型:
type SomeFuncType = (x: string, y: number) => boolean;
type SomeFuncParams = Parameters<SomeFuncType>; // [x: string, y: number]
type SomeFuncRet = ReturnType<SomeFuncType>; // boolean
至于你的runThis()
function,我倾向于给它以下类型和实现,假设你想要编译和运行的最小更改:
function runThis<K extends PropertyKey, F extends Record<K, (...args: any[]) => any>>(
funcName: K, funcObject: F
) {
const [value, setValue] = React.useState();
const theChosenFunction = (...props: Parameters<F[K]>): void => {
const result = funcObject[funcName](...props);
if (result) {
setValue(result);
}
}
return {
theChosenFunction
}
}
我给了 function 两个泛型类型参数: K
,对应于funcName
的类型,和F
,对应于funcObject
的类型。 约束K extends PropertyKey
和F extends Record<K, (...args: any[])=>any>
保证funcName
将是类似键的类型( string
、 number
或symbol
),并且funcObject
将在该键处具有函数值属性。
然后,我们可以使theChosenFunction
使用spread 和rest 语法,以允许使用可变参数列表调用function。 所以(...props) => funcObject[funcName](...props)
将接受任意数量的参数(包括零)并将它们传递给被调用的 function。 TypeScript 将此类参数列表表示为元组类型。 因此,让theChosenFunction
的调用签名看起来像(...props: Parameters<F[K]>) => void
意味着它将接受与键funcName
处的funcObject
中的条目相同的参数,并且它不会output 任何东西(因为您的实现没有 output 任何东西)。
让我们看看它是否有效:
const result = runThis('noParamsNoReturn', listOfFunctions());
result.theChosenFunction(); // okay
result.theChosenFunction('someId'); // error! Expected 0 arguments, but got 1.
const anotherResult = runThis('propsAndReturn', listOfFunctions());
anotherResult.theChosenFunction(); // error! Expected 1 arguments, but got 0.
anotherResult.theChosenFunction("someId"); // okay
runThis(listOfFunctions(), 'someId'); // error! '
// FunctionInterface' is not assignable to 'string | number | symbol'.
runThis('foo', listOfFunctions()); // error!
// Property 'foo' is missing in type 'FunctionInterface'
runThis(
'bar',
{ bar: (x: string, y: number, z: boolean) => { } }
).theChosenFunction("hey", 123, true); // okay
在我看来很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.