相交对象时,字符串文字与字符串类型不兼容

时间:2018-08-13 16:38:00

标签: flowtype

我正试图绕过Flow。

这按预期工作:

// @flow

type FontName = string
const doSomethingWithFontName = (fontName: FontName) => console.log(fontName)

type StrictFontName = 'Arial' | 'Verdana' | 'Times'
const doSomethingWithStrictFontName = (fontName: StrictFontName) => doSomethingWithFontName(fontName)

doSomethingWithStrictFontName('Times')

doSomethingWithFontName呼叫doSomethingWithStrictFontName可以正常工作。我猜Flow看到我的枚举StrictFontName仅包含字符串,因此我可以使用字符串或doSomethingWithFontName

来调用StrictFontName

但是将变量包装到对象中会失败:

// @flow

type Typography = { 
  fontName?: string; 
}
const doSomethingWithTypography = (typography: Typography) => console.log(typography)

type StrictTypography = Typography & { 
  fontName?: 'Arial' | 'Verdana' | 'Times'; 
}
const doSomethingWithStrictTypography = (typography: StrictTypography) => {
  doSomethingWithTypography(typography)
}

doSomethingWithStrictTypography({fontName: 'Times'})

我只在这里将严格的对象转发给一个更松散的函数,为什么这不起作用?流可以告诉StrictTypography的{​​{1}}仍然是字符串吗?

我已经阅读了thread,并提出了将超类型作为接口的解决方法:

fontName

这似乎可行,但是我不确定这是否是正确的方法。另外,如果我导入此接口,则会得到// @flow // Interface instead of type interface Styles { fontName?: string; } const doSomethingWithStyling = (styles: Styles) => console.log(styles) type StrictStyles = Styles & { fontName?: 'Arial' | 'Verdana' | 'Times'; } const doSomethingWithStrictStyling = (styles: StrictStyles) => { doSomethingWithStyling(styles) } doSomethingWithStrictStyling({fontName: 'Times'}) ...

您可以找到游乐场here

1 个答案:

答案 0 :(得分:2)

这里发生了两件事。

通过定义交集Styles & { fontName?: 'Arial' | 'Verdana' | 'Times' },您可以创建一个类型,该类型可能具有属性fontName,该属性必须为string类型,并且也是您放置的特定字符串之一。这是不可能的,因为如果字符串是'Verdana'或其他东西,那么它也不能是任何其他字符串。这是一个怪异的概念,但是基本上是通过将类型缩小到特定字符串来表示您不能使用其他字符串。通过将其设置为string,您可以说它可以是任何字符串。此类型无法实现。

它在第一个示例中起作用的原因是由于variance。基本上,第一个功能更广泛的函数接受string,但是由于它是一个函数参数,因此它是 contravariant ,并允许使用不太具体的类型,例如'foo''bar',是的,'Verdana'。 Flow会自动将函数参数类型解释为协变,而将函数返回类型解释为协变。

所以您可能打算这样做:

type StrictTypography = { 
  fontName?: 'Arial' | 'Verdana' | 'Times'; 
}

但是它仍然不起作用,因为尽管参数是互变的,但是对象属性fontName不是 ,所以现在只能由宽泛的string来满足以及非常广泛的string。要使其互变,请使用+符号:

type Typography = {
  +fontName?: string; 
}

Completed example.