Flow如何解释通用类型?

时间:2019-04-17 21:50:39

标签: flowtype

我想学习Flow如何确定泛型使用哪种类型,以及是否有一种方法可以控制推断出该泛型的级别(我的意思在下面进一步解释)。

  

这个问题的灵感来自How to type a generic function that returns subtypes。我认为这两个问题之间是有区别的,因为这个问题着重于了解如何选择T,而链接时着重于键入函数的返回类型。

身份功能是一个很好的例子。它的类型相当简单

function identity<T>(value: T): T;

这似乎是足够的信息,可以知道实现应该是什么。但是,我觉得这种类型不足以知道身份功能的实际作用。例如,我们可以(链接的问题尝试这样做)

function identity<T>(value: T): T {
  if (typeof value === 'string') {
    return '';
  }

  return value;
}

Try Flow

这不进行类型检查,Flow抱怨返回空字符串。但是,我想在许多种语言中都可以-在输入string时返回一个string,否则我们返回类型为{{1 }}-但由于某些原因,Flow不喜欢这样。

this answer使我们感到困惑,在这里我们可以返回value而不是空字符串,并且Flow将不再抱怨,并且无法返回严格相等的值,

T

Try Flow

我认为造成这种差异的主要原因是,除了“ JavaScript类型”外,文字还可以像Flow中的类型一样工作。例如,

value.substr(0, 0)

都有效。但是,这意味着当我们拥有类型function identity<T>(value: T): T { if (value === '') { return ''; } return value; } 的函数时,我们不知道Flow是否将文字或JavaScript类型作为类型推断。

我想知道是否有某种方法可以了解Flow对函数中的泛型类型的推断,或者是否有一种方法可以将泛型类型的作用域限定为“文字”级别或“ JavaScript”级别。使用此功能,我们可以键入将值强制转换为该类型的默认值的函数(即,字符串将变为空字符串,数字将变为0)。在这里,函数的类型实际上是const x: 5 = 5; // literal type const x: number = 5; // JavaScript type ,但是希望可以防止Flow抱怨返回默认值。

1 个答案:

答案 0 :(得分:4)

希望在这里阐明所发生的事情,如果不能直接回答问题的话。

让我们首先举一个例子:

function identity<T>(value: T): T {
  if (typeof value === 'string') {
    return '';
  }

  return value;
}

函数签名为identity<T>(T): T。基本上是这样说的:

  1. 我们正在创建一种新型T,它可以是任何类型(<T>)。
  2. 我们的函数将接收类型为T的单个参数。
  3. 我们的函数将返回类型为T的值。

从现在开始,这些限制都不会改变,T的类型也不会改变。 identity必须返回T exact 类型,而不是其类型的子集。让我们看看为什么。

identity<'some string'>('some string');

在这种情况下,T的类型是文字类型'some string'。在调用上述函数的情况下,我们将发现typeof value === 'string'并尝试返回'',即stringstringT的超类型,它是'some string',因此我们违反了该函数的约定。

对于简单的字符串,这一切似乎都是人为的,但这实际上是必要的,并且在扩展为更复杂的类型时更为明显。

让我们看看我们奇怪的身份功能的正确实现:

function identity<T>(value: T): T | string {
  if (typeof value === 'string') {
    return '';
  }

  return value;
}

只有完全匹配T的东西才能满足T的返回类型,在我们签名的情况下,返回值只能是value。但是,我们有一个特殊情况,其中identity可能返回string,因此我们的返回类型应该是T | string的并集(或者,如果我们想成为超级特定对象,则{{1 }}。

现在让我们继续第二个示例:

T | ''

在这种情况下,流只是不支持function identity<T>(value: T): T { if (value === '') { return ''; } return value; } 作为优化机制。流的细化非常挑剔,我喜欢将其看作是在我的代码上运行的一些简单正则表达式的列表。实际上,只有将类型细化为字符串的唯一方法,那就是使用value === ''。其他比较不会细化为字符串。精炼泛型肯定也​​有一定的把握,但是类似的事情很好用(精炼确实可以,但是仍然表现出先前与泛型相关的错误):

typeof value === 'string'

Try

对于function identity<T>(value: T): T { if (typeof value === 'string' && (value: string) === '') { return ''; } return value; } 示例,在我看来这绝对是一个错误。似乎您可以对substr上返回String的任何方法执行相同的操作,例如stringconcat

  

我想知道是否有某种方法可以知道Flow对函数中的泛型类型的推断

在函数体内,流程实际上并不能推断出泛型的类型。泛型具有具体定义(sliceT,本质上是未知类型,除非它具有边界,在这种情况下,它是与这些边界匹配的未知类型)。 Flow可能会推断出调用该函数的参数类型,但这与函数的编写方式无关。

  

或是否有办法将通用类型的范围限定为“文字”   级别或“ JavaScript”级别。有了这个能力,我们可以输入功能   将值强制转换为该类型的默认值(即字符串)   将转到空字符串,数字将变为0)。这里的类型   该函数实际上是T => T,但希望Flow可以是   避免抱怨返回默认值。

这里的问题是,它将不再是T。如上所示,破坏这样的实现很简单。