【问题标题】:How do I express to flow that a function must polymorphically return the same type as the first parameter?我如何表达一个函数必须多态地返回与第一个参数相同的类型?
【发布时间】:2017-07-21 00:46:45
【问题描述】:

我一直在阅读有关泛型的文章,并想了解泛型在流程中的工作原理。

https://flow.org/en/docs/types/generics/#toc-function-types-with-generics

我对使用流检查函数式编程的函数签名的想法特别感兴趣。

但是我不明白为什么以下方法不起作用:

当我尝试时

/* @flow */

const identity = (c) => c;

(identity: <T>(T) => T); // force flow to typecheck

然后Flow返回错误:

3: const identity = (c) => c;
                           ^ T. This type is incompatible with
5: (identity: <T>(T) => T);
    ^ some incompatible instantiation of `T`

我会认为因为 c 始终是 c 并且没有被变异,所以它的类型必须与模式匹配?

问:如何表示函数必须返回与第一个参数相同的类型?


补充示例

即使我尝试使用类型别名,它似乎也不起作用。

/* @flow */
type ReturnsSameTypeAsFirstParam = <T>(T) => T;

const identity:ReturnsSameTypeAsFirstParam = (c) => c;

然后我得到:

4: const identity:ReturnsSameTypeAsFirstParam = (c) => c;
                                                       ^ T. This type is incompatible with
4: const identity:ReturnsSameTypeAsFirstParam = (c) => c;
                                                ^ some incompatible instantiation of `T`

编辑:尝试澄清

我主要热衷于为函数提供一种类型作为参数,并了解如何以多态方式使用它们。

也许这是我尝试键入的内容的更清晰示例:

/* @flow */

type Transformer = <T>(T)=>T;

function transformAGivenThing(transform:Transformer, thing:*) {
  return transform(thing);
}

function transformAString(str:string):string {
  return str.toUpperCase();
}

transformAGivenThing(transformAString, 'thing');

这会在我运行流程时导致这些错误:

3: type Transformer = <T>(T)=>T;
                       ^ T. This type is incompatible with the expected param type of
9: function transformAString(str:string):string {
                             ^ string
9: function transformAString(str:string):string {
                                         ^ string. This type is incompatible with the expected param type of
13: transformAGivenThing(transformAString, 'thing');
                     ^ some incompatible instantiation of `T`

【问题讨论】:

    标签: javascript generics flowtype


    【解决方案1】:

    编辑关于添加到您的帖子。

    /* @flow */
    
    const isStr = (str: string) => !!str;
    const isNmbr = (nmbr: number) => !!nmbr;
    
    function transformAny<T>(transformer: (T) => T, thing: T): T {
      return transformer(thing);
    }
    
    function transformString(thing: string): string {
      return !!thing ? thing.toUpperCase() : thing;
    }
    
    function transformNumber(thing: number): number {
      return !!thing ? thing * 10 : thing;
    }
    
    let s = transformAny(transformString, "1");
    
    let n = transformAny(transformNumber, 5);
    
    isStr(s);
    // isStr(n);
    // isNmbr(s);
    isNmbr(n);
    

    取消注释 2 次类型检查调用将引发参数类型不匹配的错误。我认为您不能为其中一个参数声明自定义类型并返回相应的类型。这是我第一次看到这种语言,但它看起来非常类似于 TypeScript。

    【讨论】:

    • 嗯,也许我对我在这里想要实现的目标不够清楚。我会尝试更新我的问题。
    • @rickard 我已经编辑了我的帖子。这是您要对通用对象 transformer 执行的操作吗?
    【解决方案2】:

    好的,所以我最终提交了一个问题以询问如何执行此操作。他们的回答:

    /* @flow */
    
    type Transformer<T> = (T)=>T;
    
    function transformAGivenThing(transform:Transformer<*>, thing:*) {
      return transform(thing);
    }
    
    function uppercaseAString(str:string):string {
      return str.toUpperCase();
    }
    
    console.log(transformAGivenThing(uppercaseAString, 'thing'));
    

    https://github.com/facebook/flow/issues/4429

    发生的情况是您需要使用 Type 配置 Transformer 泛型类型,但在这种情况下,因为它需要是多态的,所以配置应该是 *

    【讨论】:

    • 调用let s = transformAGivenThing(uppercaseAString, 'thing');时,返回类型为any。如果您检查我更新的答案,返回类型对应于给定transformer 的返回类型。适当的智能感知会发现这一点。
    • *any 之间存在差异。 * 表示将类型检查推迟到下游,而any 表示不进行类型检查。因为* 将类型检查推迟到以后,所以在上面的示例中,泛型中的类型解析为流检查uppercaseAString 函数的点。
    猜你喜欢
    • 1970-01-01
    • 2011-09-11
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    相关资源
    最近更新 更多