facebook/flow

Strange "unconstrained" behavior with React components

ansonlouis opened this issue · 5 comments

I'm seeing what I believe to be unexpected pass-cases and, in general, inconsistent behavior with underconstrained component props. I've boiled down the example to something simple enough to illustrate the problem but still gets to the brunt of my real-world use-case.

The general premise is being able to have:

  • a union of types (with type and state fields)
  • a component that will take in the common type field as well as take in a component that should expect the corresponding state

In general, I've gotten Flow to handle this well (albeit inconsistently) until I start nesting the component in something else (even just a <div/>)

Example:

type Data1 = {type: 'one', state: 1};
type Data2 = {type: 'two', state: 2}; 

type DataSource =
    | Data1
    | Data2;

type Props<D: DataSource> = {
    type: D['type'],
    C: ComponentType<{s: D}>
};

function DataComponent<D: DataSource>({type, C}: Props<D>): Node { ... }

// good
<DataComponent type="one" C={(p: {s:Data1}) => <div/>} />;
<DataComponent type="two" C={(p: {s:Data2}) => <div/>} />;
// expected failure
<DataComponent type="two" C={(p: {s:Data1}) => <div/>} />;

Looking at the TryFlow link below, Flow handles this situation well except in the last cases, which I'm not sure why. This feels like a bug, but maybe I'm missing something.

Try Flow

This is expected behavior. The difference is caused by whether the generic react component has some typing context coming from the parent. If there is a usable typing context, then even if some type argument cannot be solved from arguments and return hints, we will happily use default of the type parameter or bound (mixed if not specified) of the type parameter as the solution.

So the react element tree changes typing context?

function Component<T: number>(pprops: {a:T}): Node {}

// pass (good)
<Component a={1} />;

// fail (good)
<Component a="str" />;

// pass?
(
    <div>
        <Component a={true} />
    </div>
)

TryFlow

The new example seems like a bug. I will reopen and investigate.

Thanks. Sorry, it took me a second to realize the issue could be boiled down more simply

198.2 seems to fail properly, anyways