我正在构建一个函数管道,它创建一系列检查/保护,然后接受一个函数并返回一个函数,该函数要么提前返回,要么调用接受的函数。
// A generic function type. The goal is to have the pipeline work with any type of function
interface GoalFunctionType { (): string }
// Pipeline instantiation and usage `checkSomething` and `provideName` are example functions in the pipeline, they are not implemented here.:
const p = new FunctionPipeline<GoalFunctionType>()
const passedInFunction = ({ name }: { name: string }) => "Hello " + name
const goalFunction: GoalFunctionType = p.checkSomething().provideName().finally(passedInFunction);
在finally
中,流水线检查会触发提前返回,它们可以选择为传入finally的函数创建额外的参数,就像上面的provideName
一样(但下面的实现还没有达到这个程度)。
我被finally
函数的类型检查器卡住了。我希望类型检查器确保传入的函数
- 具有与
GoalFunctionType
相同的返回类型 - 接受与
GoalFunctionType
相同的参数 - 接受其他管道生成的参数作为第一个参数中的命名参数(此处未实现)
下面是一个最小实现(CodeSandbox),编译时没有出现错误/警告:
class FunctionPipeline<FunctionType extends (...args: any[]) => any> {
finally(
fn: (...args: Parameters<FunctionType>) => ReturnType<FunctionType>
): FunctionType {
return (...args) => {
return fn(...args);
};
}
}
interface LoaderFunction {
({ name }: { name: string }): string;
}
const goalFunction = new FunctionPipeline<LoaderFunction>().finally(
({ name }) => {
const result = `Hello ${name}`;
console.log(result);
return result;
}
);
const app = document.getElementById("app");
if (app) app.innerHTML = goalFunction({ name: "World" });
为了实现流水线生成的参数,finally函数应该更像这样,并希望具有特定的类型:
fn: (pipelineArgs: GeneratedArgsType, ...args: Parameters<FunctionType>) => ReturnType<FunctionType>
): FunctionType {
return (...args) => {
// example: this.generatedArgs == { name: "Nathan" };
return fn(this.generatedArgs, ...args);
};
}
functionPipeline.finally
方法有两个编译器错误。
第一次返回时出错:
Type '(...args: any[]) => ReturnType<FunctionType>' is not assignable to type 'FunctionType'.
'(...args: any[]) => ReturnType<FunctionType>' is assignable to the constraint of type 'FunctionType', but 'FunctionType' could be instantiated with a different subtype of constraint '(...args: any[]) => any'.
第二次返回时出错:
(parameter) args: any[]
Argument of type 'any[]' is not assignable to parameter of type 'Parameters<FunctionType>'.
你能帮我找出正确的类型来实现我的目标吗?这是minimal example in CodeSandbox。如果你想看到更多的代码,check out this longer example that provides more application context and usage in the Remix framework。
1条答案
按热度按时间xvw2m8pv1#
您的版本正在生成错误,因为无法保证在调用
finally()
时FunctionPipeline<F>
可以生成F
类型的generic值。F
可以是任何函数类型的任何子类型,包括具有额外属性的函数:这会在运行时崩溃,因为
typeof foo
已知具有strProp
属性,而您的finally()
实现没有。无论如何,您并不真正关心函数类型
F
;如果你在调用new FunctionPipeline<F>()
时不依赖于手动指定类型参数,那么我建议你应该重构以使用你关心的两种类型:这更直接,因为,例如,
finally()
产生(...args: A) => R
类型的函数。但是,假设这是不可接受的,另一种方法是从
F
计算A
和R
,然后完全丢弃F
。因此
FunctionPipeline<F>
的finally()
方法返回(...args: Parameters<F>) => ReturnType<F>
类型的值,并且不声明返回F
类型的值,这就解决了我在foo
中所展示的问题:现在编译器认为
gf.finally(foo)
没有strProp
属性,你的示例代码也可以工作:Playground代码链接