我有一个函数foo
:
function foo(a: string, b: string, c: number, d: boolean): Promise<Result> {
return new Promise(resolver => {
...
});
}
// use foo
foo('hello', 'world', 3, true).then(...);
和一个高阶函数,它采用函数,然后是使用柯里化(Currying)的参数:
function hof(func: Function) {
return async function (...args: any[]) {
// forward the args to the func and get the result
const result = await func(...args);
// do something else with the result
}
}
// use foo with higher-order function `hof`
hof(foo)('hello', 'world', 3, true);
^^^^^^^^^^^^^^^^^^^^^^^^^ lack type annotations
使用方法flowtype注释
hof
的整个部分功能:...args
: 使用 any[]
将丢失原始类型 最佳答案
TL;DR
我仍在寻找更好的选择,但到目前为止这对我有用:
function foo(a: string, b: string, c: number): string {
return 'Yay!'
}
// Alternatively, interface Arguments {
type Arguments = {
<A>((A) => any): [A],
<A, B>((A, B) => any): [A, B],
<A, B, C>((A, B, C) => any): [A, B, C],
<A, B, C, D>((A, B, C) => any): [A, B, C, D],
}
function hof <T: Function> (t: T): (...$Call<Arguments, T>) => void {
return (...args) => undefined;
}
hof(foo);
hof(foo)("This", "works", 2);
// hof(foo)("this", "should't", "work");
// hof(foo)("Correctly", "fails", 2, "when there are extra args");
我遇到了类似的问题。也就是说,键入一个函数,该函数接受一个具有特定参数集的函数并返回一个接受相同参数集的新函数,但我找不到明确的答案。
加长版
这是研究流类型问题并尝试错误的结果。 These are all the variations I tried that work in some degree
function foo(a: string, b: string, c: number): string {
return 'Yay!'
}
// Attempt 1:
// Taken from
// https://github.com/facebook/flow/issues/4672#issuecomment-377649789
declare function arguments<A>((A) => any): [A]
declare function arguments<A, B>((A, B) => any): [A, B]
declare function arguments<A, B, C>((A, B, C) => any): [A, B, C]
declare function arguments<A, B, C, D>((A, B, C, D) => any): [A, B, C, D]
type Arguments<T> = $Call<typeof arguments, T>
function hof1 <T: Function> (t: T): (...Arguments<T>) => void {
return (...args) => undefined;
}
const augmentedFn = hof1(foo)("This", "works", 2);
// const augmentedFn2 = hof1(foo)("this", "should't", "work");
// const augmentedFn2 = hof1(foo)("Also", "check", 2, "number of args");
// Attempt 2: using array of mixed.
// This one doesn't seem to have limit to the arguments you can provide,
// but it doesn't seem to fail when extra args are passed.
// Notice that the return type is specified in the function signature
function hof2 <T: Array<mixed>>(func: (...T) => any): (...args: T) => any {
return (...args) => null;
}
hof2(foo)("2", "2", 1);
// hof2(foo)(1, "this fails correctly", 1);
hof2(foo)("2", "2", 1, "This one has extra arg, but this method can't limit them");
// If we define the generic return type in the returned function, flow breaks
function hof2broken <T: Array<mixed>>(func: (...T) => any) {
return (...args: T) => null;
}
// hof2broken(foo)("This should work", "but fails with a cryptic message", 1);
// Attempt 3, using generics to capture the tuple values.
// It requires us to declare one generic for each arg in any function
// that uses them. Notice that I have to redeclare all the A, B, C and D generic
// types just to pass them to the tuple type.
type genericTuple<A, B, C, D> = [A] | [A, B] | [A, B, C] | [A, B, C, D]
function hof3<A, B, C, D, T: genericTuple<A, B, C, D>>(func: (...T) => any): (...args: T) => any {
return (...args) => null;
}
hof3(foo)("This", "works", 2);
// hof3(foo)("this", "should't", "work");
hof3(foo)("Also", "fails", 2, "to check the argument's length");
// hof3(foo)("Also", "fails", 2, "to check the argument's length", "until it exceeds the number of possible args");
// Attempt 4
// It seems to be possible to ommit the generics by using tuples of 'any'
// This seems to have the same issues of not checking for extra unwanted args
type anyTuple = [any] | [any, any] | [any, any, any] | [any, any, any, any]
function hof4<T: anyTuple>(func: (...T) => any): (...args: T) => any {
return (...args) => null;
}
hof4(foo)("This", "works", 2);
// hof4(foo)("this", "should't", "work");
hof4(foo)("Also", "fails", 2, "to check the argument's length");
// Attempt 5:
// Trying to extract the type calculated in
// https://github.com/facebook/flow/issues/4672#issuecomment-377649789
// without getting redeclaration warnings
// This works in the 'try' console, but doesn't in the 0.80.0 version
// in Mac OS, so I can't stick with it
// I think that this working on the 'try' console is probably a bug
type ArgsFrom<T> = $Call<
(<A>((A) => any) => [A]) &
(<A, B>((A, B) => any) => [A, B]) &
(<A, B, C>((A, B, C) => any) => [A, B, C]) &
(<A, B, C, D>((A, B, C, D) => any) => [A, B, C, D]), T>
// type Arguments2<T> = $Call<argtest, T>
function hof5 <T: Function> (t: T): (...ArgsFrom<T>) => void {
return (...args) => undefined;
}
let testVar = hof5(foo);
hof5(foo)("This", "works", 2);
// hof5(foo)("this", "should't", "work");
// hof5(foo)("Correctly", "fails", 2, "when there are extra args");
// Attempt 6: I read somewhere that overloading is supported
// on interfaces, so I gave it a try. It seems to work and I will stick with it.
type Arguments3 = {
<A>((A) => any): [A],
<A, B>((A, B) => any): [A, B],
<A, B, C>((A, B, C) => any): [A, B, C],
<A, B, C, D>((A, B, C) => any): [A, B, C, D],
}
function hof6 <T: Function> (t: T): (...$Call<Arguments3, T>) => void {
return (...args) => undefined;
}
hof6(foo);
hof6((a: string, b: boolean) => null)("Also works", true);
hof6(foo)("This", "works", 2);
hof6(foo)("this", "should't", "work");
hof6(foo)("Correctly", "fails", 2, "when there are extra args");
// Yay! Works and kind of makes sense
关于flowtype:如何使用参数转发注释高阶函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41338664/