如何在使用Flow时将道具传播到使用精确道具的React组件?

时间:2018-02-17 15:31:47

标签: javascript reactjs flowtype

请考虑以下使用流量道具的示例。

import * as React from 'react';

type FooProps = {| 
  foo: number,
  bar?: string 
|};

class Foo extends React.Component<FooProps> {}

我们有React组件类Foo,它接受​​一个确切的props对象。我们希望强制执行准确性,以便用户不会无意中对其道具进行拼写错误(例如baz,当他们打算使用bar时)。

这非常正常,错误会按预期发生。

但是,如果我们想从其他地方向这个组件传播道具呢?例如:

const f = (props: FooProps) => <Foo {...props} />;

Flow会给我们一个关于props的准确性的错误:

10: const f = (props: FooProps) => <Foo {...props} />;
                                    ^ Cannot create `Foo` element because inexact props [1] is incompatible with exact `FooProps` [2].
References:
10: const f = (props: FooProps) => <Foo {...props} />;
                                   ^ [1]
8: class Foo extends React.Component<FooProps> {}
                                     ^ [2]

忽视这个论点,&#34;当你要求准确性时,你不应该将道具传播给那些组件,如何实现传播?

我确实找到了一种方法来执行此操作,但它使用了未记录的实用程序类型$Shape<T>code)。目前还不清楚这是否有任何后果或副作用,但它似乎正常工作:

class Foo extends React.Component<$Shape<FooProps>> {}

这里有一个link to try out what I've got using $Shape<T>,其中包含我希望错误的项目(而不是):

2 个答案:

答案 0 :(得分:2)

如果这不是来自官方来源,请道歉。

解决方案:在传播之前将投射道具键入any

它符合您在功能中传播的要求。该功能可确保在类型转换之前的准确性。

注意:演员表上的$Shape<FooProps>不起作用,它仍然认为是准确的。也没有将props分配给const spreadable: $Shape<FooProps> = props似乎$Shape不会删除准确性,尽管在您的示例中出现了。无论如何,你必须剥离正确性,并在内部执行该功能似乎是合理的。

The Flow docs discuss type casting via any as legitimate虽然潜在的不安全而且不推荐(因为你放松了类型安全)。我认为在上下文中它是合理的。

import * as React from 'react';

type FooProps = {| 
  foo: number,
  bar?: string 
|};

class Foo extends React.Component<FooProps> {}

const f = (props: FooProps) => <Foo {...(props: any)} />;

f({foo: 1})                     // PASS: with foo, without bar
f({foo: 1, bar: ''})            // PASS: with foo and bar
{ <Foo foo={1} /> }             // PASS: with foo, without bar
{ <Foo foo={1} bar="" /> }      // PASS: with foo and bar

f({})                           // FAIL: missing foo
f({foo: ''})                    // FAIL: wrong type of foo
f({foo: 1, bar: 1})             // FAIL: with foo, wrong type of bar
f({foo: 1, x: 1})               // FAIL: unexpected x
{ <Foo /> }                     // FAIL: missing foo
{ <Foo foo="" /> }              // FAIL: wrong type of foo
{ <Foo foo={1} bar={1} /> }     // FAIL: with foo, wrong type of bar
{ <Foo foo={1} x={1} /> }       // FAIL: unexpected x

Try it here

答案 1 :(得分:1)

看起来这是一个非常常见的问题:Exact fails when doing es6 object spread

该线程中建议的一个选项是使用:

type Exact<T> = T & $Shape<T>

然后不要{||}完全一致地编写您的类型:

type FooProps = {
  foo: number,
  bar?: string 
}

class Foo extends React.Component<Exact<FooProps>> {}

这将允许您使用spread运算符并仍然可以自动完成属性。