Typescript动态函数的键/值的对象



是否有一种方法可以根据初始接口设置函数?我有一堆listfunctions和等量的接口,它们包含函数的类型。我想创建一个返回自定义钩子的工厂。这个想法是为了节省大量的代码,使编辑和添加功能到所有的钩子都是轻而易举的。

FunctionInterface是所有函数名及其返回值。

listOfFunctions是一个设置函数(实际代码中有一个配置),它返回一个带有函数列表的对象。

theChosenFunction是一个将在钩子中返回的函数,它允许我与listfunction函数之一交互。这意味着参数(如果需要)。实际应用中的函数是promise,它将设置钩子的状态。在这个例子中,我只返回一个值和setState。

A)这是可能做与funcObject[funcName]()和创建一个函数调用typescript?这将需要添加参数或不添加参数的能力。

B)是否有方法获得函数类型的返回值?所以在这个例子中:type CanThisWork = () => string;我想提取string;我们的想法不是对所有的listfunction和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>实用程序类型,它们接受函数类型T,并使用条件类型推断分别提取参数元组和返回类型:

type SomeFuncType = (x: string, y: number) => boolean;
type SomeFuncParams = Parameters<SomeFuncType>; // [x: string, y: number]
type SomeFuncRet = ReturnType<SomeFuncType>; // boolean

对于您的runThis()函数,假设您希望对编译和运行进行最小的更改,我倾向于给它提供以下类型和实现:

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
}
}

我给了函数两个泛型类型参数:K,对应funcName的类型,F,对应funcObject的类型。约束K extends PropertyKeyF extends Record<K, (...args: any[])=>any>保证funcName将是类似键的类型(stringnumbersymbol),并且funcObject将在该键上具有函数值属性。

然后,我们可以使theChosenFunction使用扩展和rest语法,以允许使用可变参数列表调用函数。因此,(...props) => funcObject[funcName](...props)将接受任意数量的参数(包括0)并将它们传递给被调用的函数。TypeScript将这样的参数列表表示为元组类型。因此,让theChosenFunction的调用签名看起来像(...props: Parameters<F[K]>) => void意味着它将接受与funcObject中键funcName的条目相同的参数,并且它不会输出任何内容(因为您的实现不输出任何内容)。


让我们看看它是否有效:

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

看起来不错。

Playground链接到代码

最新更新