我想学习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;
}
这不进行类型检查,Flow抱怨返回空字符串。但是,我想在许多种语言中都可以-在输入string
时返回一个string
,否则我们返回类型为{{1 }}-但由于某些原因,Flow不喜欢这样。
this answer使我们感到困惑,在这里我们可以返回value
而不是空字符串,并且Flow将不再抱怨,并且无法返回严格相等的值,
T
我认为造成这种差异的主要原因是,除了“ 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抱怨返回默认值。
答案 0 :(得分:4)
希望在这里阐明所发生的事情,如果不能直接回答问题的话。
让我们首先举一个例子:
function identity<T>(value: T): T {
if (typeof value === 'string') {
return '';
}
return value;
}
函数签名为identity<T>(T): T
。基本上是这样说的:
T
,它可以是任何类型(<T>
)。T
的单个参数。T
的值。从现在开始,这些限制都不会改变,T
的类型也不会改变。 identity
必须返回T
的 exact 类型,而不是其类型的子集。让我们看看为什么。
identity<'some string'>('some string');
在这种情况下,T
的类型是文字类型'some string'
。在调用上述函数的情况下,我们将发现typeof value === 'string'
并尝试返回''
,即string
。 string
是T
的超类型,它是'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
的任何方法执行相同的操作,例如string
或concat
。
我想知道是否有某种方法可以知道Flow对函数中的泛型类型的推断
在函数体内,流程实际上并不能推断出泛型的类型。泛型具有具体定义(slice
是T
,本质上是未知类型,除非它具有边界,在这种情况下,它是与这些边界匹配的未知类型)。 Flow可能会推断出调用该函数的参数类型,但这与函数的编写方式无关。
或是否有办法将通用类型的范围限定为“文字” 级别或“ JavaScript”级别。有了这个能力,我们可以输入功能 将值强制转换为该类型的默认值(即字符串) 将转到空字符串,数字将变为0)。这里的类型 该函数实际上是T => T,但希望Flow可以是 避免抱怨返回默认值。
这里的问题是,它将不再是T
。如上所示,破坏这样的实现很简单。