【问题标题】:How to annotate high order function with arguments forwarding如何使用参数转发注释高阶函数
【发布时间】:2020-01-14 12:53:07
【问题描述】:

我正在尝试注释此作文:

const get1 = (n: number, s: string) => `${n}_${s}`;
const get2 = (s: string, n: number) => `${n}_${s}`;

const foo = (get) => (...args) => {
    get(...args);
}

const foo1= foo(get1);
const foo2= foo(get2);


foo1(2, 'qwe');
foo2('qwe', 1)

目前我使用 Flow 作为类型检查器,但我也对 TypeScript 答案感兴趣,因为它可能是我迁移的好点。

【问题讨论】:

  • 这是apply 函数,很难以有意义的方式进行注释。因为get 可以是具有任何输入和任何输出的任何函数,而...args 可以是任何类型,所以apply 变为“任何函数和任何参数,产生任何输出”...
  • 比较一下 const foo = <A, B> (get: A => B, x: A): B => get (x) 有一个有意义的注解

标签: javascript typescript types flowtype


【解决方案1】:

这是流程版本:

const get1 = (n: number, s: string) => `${n}_${s}`;
const get2 = (s: string, n: number) => `${n}_${s}`;

const foo = <A: mixed[], R>(get: (...A) => R): ((...A) => R) => 
  (...args: A): R =>
    get(...args);

const foo1= foo(get1);
const foo2= foo(get2);


foo1(2, 'qwe');
foo2('qwe', 1);
// $ExpectError
foo1('qwe', 2);
// $ExpectError
foo2(2, 'qwe');

foo2('qwe', 1, 3); // this should probably error but doesn't

(Try)

【讨论】:

    【解决方案2】:

    想出了以下解决方案:

    // @flow
    
    const get1 = (n: number, s: string) => `${n}_${s}`;
    const get2 = (s: string) => `_${s}`;
    
    type Apply<T, R> = (...args: T) => R
    
    const foo = <TArgs: *>(get: Apply<TArgs, string>): Apply<TArgs, Promise<*>> =>
        (...args) => {
            const str = get(...args);
    
            return Promise.resolve(str);
        }
    
    
    const foo1= foo(get1);
    const foo2= foo(get2);
    
    
    foo1(1, 'qwe');
    foo2('qwe');
    
    // $ExpectError      
    foo2('qwe', 'qwer') //wrong arity
    // $ExpectError 
    foo2('qwe', 2, 3, 5, 6, 4) //wrong arity
    // $ExpectError 
    foo1(1, 'qwe', 3, 5, 6) //wrong arity
    
    

    这个例子还有一个补充,我没有返回 get 的结果,而只是在函数内部使用它。

    看起来它几乎可以正常工作。缺少的一件事是 foo1 和 foo2 的数量。但至少类型检查可以正常工作

    感谢大家的回答

    【讨论】:

    • 这使用了已弃用的存在运算符*
    • 哈哈,没有注意到它何时被弃用。我从 Flow 文档中记得的最后一件事是,他们建议使用 * 而不是 any,因为它可以更好地工作
    【解决方案3】:

    您可以在此示例中使用以下方法:

    const get1 = (n: number, s: string) => `${n}_${s}`;
    const get2 = (s: string, n: number) => `${n}_${s}`;
    
    const foo = <T extends any[], R>(get: (...args: T) => R) => (...args: T): R => {
      return get(...args);
    };
    
    const foo1 = foo(get1);
    const foo2 = foo(get2);
    
    foo1(2, "qwe");
    foo2("qwe", 1);
    

    TypeScript Playground

    如果您不熟悉 TypeScript,则此示例依赖于 GenericsRest Parameters。具体来说,本例中的 Rest Generics 是在3.0 中添加的。

    【讨论】:

    • 来自Flow docs如果您想选择不使用类型检查器的方法,any 就是这样做的方法。 使用any 完全不安全,应尽可能避免使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多