是否有可能改进有界多态类型?

时间:2017-01-16 15:37:19

标签: flowtype

Try flow link.

这是一个简单的有界多态性示例,它并不像我期望的那样工作:

// @flow

function thisBreaks<T: 'a' | 'b'>(x: T): T {
  if (x === 'a') {
    return 'a'
  } else {
    return 'b'
  }
}

function thisWorks<T: 'a' | 'b'>(x: T): T {
  return x
}

const a = 'a'
const aPrime: 'a' = thisWorks(a)
const b = 'b'
const bPrime: 'b' = thisWorks(b)

5:     return 'a'              
               ^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {   
   ^ some incompatible instantiation of `T`

7:     return 'b'              
               ^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {   
   ^ some incompatible instantiation of `T`

我原本期望第一个例子可以工作,例如x === 'a'检查可以将T改进为'a',对吗?

1 个答案:

答案 0 :(得分:2)

这是不可能的,也不可能。这是一个显示原因的例子:

function test<T: number | string>(x: T): T {
  if (typeof x === 'number') {
    return 1;
  } else {
    return 'b'
  }
}

test((5: 5));

该函数应返回5类型的值,但返回1

那么,会发生什么?我们有一些未知类型T,我们知道T&lt ;: string | numberTstring | number的子类型)。在我们优化x之后,我们知道Tnumber的子类型。这并不意味着T number。它可以是5,如示例中所示,或1 | 2 | 3。知道Tnumber的子类型并不足以创建T的值。要做到这一点,我们需要知道T的下限,但没有办法知道它。

最后一个问题是:为什么你的例子显然是安全的呢?这很简单:如果T&lt ;: 'a',那么它只能是'a'(或empty,但它并不重要) 。 'a'没有其他子类型。所以,从理论上讲,Flow可以支持这一点,但它不太实用:如果你知道x'a',那么你可以返回x