Flow: Bounded polymorhism with React

Created on 22 Nov 2016  路  4Comments  路  Source: facebook/flow

I am probably missing something obvious here:

// @flow

import React, { Component } from 'react';

import { render } from 'react-dom';

type BasicHighlight = {
    id: string,
    text: string,
};

class HighlightList<X: BasicHighlight> extends Component {
    props: {
        items: Array<X>
    }

    render() {
        return <div>{ this.props.items.map(item => <li>{ item.text }</li>) }</div>;
    }
}

const highlights = [
    { id: '2', text: 'bla' }
];

render(<HighlightList items={ highlights }/>, document.body);
src/test.js:12
 12: class HighlightList<X: BasicHighlight> extends Component {
                            ^^^^^^^^^^^^^^ object type. This type is incompatible with
 12: class HighlightList<X: BasicHighlight> extends Component {
           ^^^^^^^^^^^^^ some incompatible instantiation of `X`

src/test.js:23
 23:     { id: '2', text: 'bla' }
         ^^^^^^^^^^^^^^^^^^^^^^^^ object literal. This type is incompatible with
 12: class HighlightList<X: BasicHighlight> extends Component {
           ^^^^^^^^^^^^^ some incompatible instantiation of `X`

tryflow.org

react

Most helpful comment

This works

class HighlightList<X: BasicHighlight> extends Component<void, { items: Array<X> }, void> {
    render() {
        return <div>{ this.props.items.map(item => <li>{ item.text }</li>) }</div>;
    }
}

because since the signature of Component is Component<DefaultProps, Props, State>, you must convince Flow that your props are compatible with Props for all Xs

Same as

class A<Props> {
  props: Props;
}

class B<X> extends A { // <= This type is incompatible with some incompatible instantiation of `X`
  props: X
}

// this is ok
class B<X> extends A<X> {}

All 4 comments

+1

Seems to work with sintax:

type Props<X> = { items: Array<X> };
class HighlightList<X: BasicHighlight> extends Component<void, Props<X>, void> {

tryflow.org

But I guess you could use

  props: {
    items: Array<BasicHighlight>
  }

directly if BasicHighlight is just a type alias.

This works

class HighlightList<X: BasicHighlight> extends Component<void, { items: Array<X> }, void> {
    render() {
        return <div>{ this.props.items.map(item => <li>{ item.text }</li>) }</div>;
    }
}

because since the signature of Component is Component<DefaultProps, Props, State>, you must convince Flow that your props are compatible with Props for all Xs

Same as

class A<Props> {
  props: Props;
}

class B<X> extends A { // <= This type is incompatible with some incompatible instantiation of `X`
  props: X
}

// this is ok
class B<X> extends A<X> {}

Given the responses with working solutions already, and that the v0.53 upgrade to React.Component typing resolved some of the confusion by making authors specify prop types, I think this can be closed. (/cc @calebmer)

Was this page helpful?
0 / 5 - 0 ratings