Flow: How should I annotate React Inheritance Inversion HoC function?

Created on 22 Mar 2017  路  12Comments  路  Source: facebook/flow

Hi, how should I annotate React Inheritance Inversion HoC function using generics? I want to inject new Foo props to WrappedComponent by Inheritance Inversion HoC without success...

/* @flow */
import React from 'react';

type Foo = {
  foo: number;
}

type Bar = {
  bar: number; 
}

function hoc<P>(
  WrappedComponent: Class<React$Component<void, P, void>>
): Class<React$Component<void, $Diff<P, Foo>, void>> {
  return class Enhancer extends WrappedComponent {
    props: $Diff<P, Foo>;
  }
}

class A extends React.Component {
  props: Bar;
}

const B = hoc(A);

const C = () => <B foo={1} bar={2}/>;

3 following errors occurred on this example.

12: function hoc<P>(    ^ some incompatible instantiation of `P`. This type is incompatible with
12: function hoc<P>(    ^ some incompatible instantiation of `P`
12: function hoc<P>(
                 ^ P. Expected object instead of
12: function hoc<P>(
                 ^ P



md5-3cf824a8e1bd48bf614f22c430040382



16:     props: $Diff<P, Foo>;
                     ^ P. This type is incompatible with
12: function hoc<P>(    ^ some incompatible instantiation of `P`

https://flowtype.org/try/#0PQKgBAAgZgNg9gdzCYAoAlgWwA5wE4AuYASgKYCGAxkVHnJmAOR4XWMDcqqBAntqWABicOGAC8YAN6owYKCIBcYAHYBXTACNSeTgF8uvfmABC5POKkywGs0rWbt7MKn2ooq5dXRxlYABZwlAA8AAoAfAAUVgDqeOTY-AAmAML0uMqkygRKyTDkAM75QWRUBAAkqTg+mQRBAG5w6IkANGAhrQ1NYWGoAJQ5eYXFrOWV6TX1jS1gZQAi6FBQoa3CcGEdU92WsiwEqni+lIP5YACiyn7kntpgpAAeBJmJJ7HxSWPVWduyYNh02PklHMFkt2kIRGFOLJ9K4jgUTgBBW4PJ4nErUAB0HwyX2ksj+cABSlMOhcXEoPnyRGMFgClAiCN6nFQFOUVLAyQsEV64jCYCCNPkcDEkgAjLprGYRQAmXTASFcIA

Most helpful comment

This was my puzzle for the evening, thank you. 馃槂

My solution:
````js
/* @flow */
import React from 'react';

type Foo = {
foo: number;
}

type Bar = {
bar: number;
}

type __UnwrapType> = T
type UnwrapType = __UnwrapType<*, T>

type ReactComponentClass>

function hoc<
T: Foo,
Component: ReactComponentClass<*>

(WrappedComponent: Component): ReactComponentClass & T> {
return class Enhancer extends WrappedComponent {
props: T
}
}

class A extends React.Component {
props: Bar
}

const B = hoc(A);

const C = () =>
````

All 12 comments

Not exactly sure what you mean by "Inheritance Inversion," but based on the API indicated here...
js const C = () => <B foo={1} bar={2}/>;

This is what I'd do:
````js
/* @flow */
import React from 'react';

type Foo = {
foo: number;
}

type Bar = {
bar: number;
}

function hoc Component: Class>
): Class> {
return class extends React.Component {
render() {
return
}
}
}

class A extends React.Component {
props: Bar;
}

const B = hoc(A);

const C = () => ;
````
https://flowtype.org/try/#0PQKgBAAgZgNg9gdzCYAoAlgWwA5wE4AuYASgKYCGAxkVHnJmAOR4XWMDcqqBAntqWABicOGAC8YAN6owYKCIBcYAHYBXTACNSeTgF8uvfmABC5POKkywGs0rWbt7MKn2ooq5dXRxlYABZwlAA8AApKkroAfAAUVgDC9LjKpMoESnEw5ADOWUFkVAQAJAk4PikEQQBucOgAJgA0YCGN1XWRkagAlOmZOXmsRSVJ5VU1DU1gAGQmZi1j7ZayLASqeL6UvVlgpAAeBCm1W-nUAHRDZamLsmAsyrXa0Z1X1zekK2tgQefJl5In-wQ-OgsidsHRsFldGBgB0XvpZPpXBtslsAILbPYHI4DM6JC5EaSyMFwCFKUw6FxcSg+LJEYwWAKUaKozqcVDU5S0sBxCyPcSRT70+RwMSSACMUJseFFACZdDDOEA

Eh, actually not what you are looking for... https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e#.5icjtqfuy

@mwalkerwells thanks!! Inheritance Inversion means extends WrappedComponent(not React.Component.). The above article is exactly that.

I want to check all props type (foo and bar in this example).

I fixed example with reference to your answer.
It works as expected but I do not know the right way....

/* @flow */
import React from 'react';

type Foo = {
  foo: number;
}

type Bar = {
  bar: number; 
}

function hoc<P: any>(
  WrappedComponent: Class<React$Component<void, P, void>>
): Class<React$Component<void, P & Foo, void>> {
  return class Enhancer extends WrappedComponent {
    props: P & Foo;
  }
}

class A extends React.Component {
  props: Bar;
}

const B = hoc(A);

const C = () => <B foo={1} bar={2}/>;
const C = () => <B foo={"1"} bar={2}/>;  // Error
const C = () => <B foo={1} bar={"2"}/>;  // Error

https://flowtype.org/try/#0PQKgBAAgZgNg9gdzCYAoAlgWwA5wE4AuYASgKYCGAxkVHnJmAOR4XWMDcqqBAntqWABicOGAC8YAN6owYKCIBcYAHYBXTACNSeTgF8uvfmABC5POKkywGs0rWbt7MKn2ooq5dXRxlYABZwlAA8AApK5Mo8AHwAFFYA6njk2PwAJgDC9LjKpMoESukw5ADOxUFkVAQAJJk4PrkEQQBucOipADRgIZ0tbVFRqACUBUWl5azVtdkNza0dXWAAZEIiPXP9lrIsBKp4vpSjxWAAosp+EZTaYKQAHgS5qUeJyWlT9XmbsmDYdNjFSiElis4JxZPpXAcSkcAILXO4PI4VagAOjeOQ+0lkPzgfyUph0Li4lB8xSIxgsAUoMWhg04qGJylJYHSFhig3EUTAQXJ8jgYkkAEZdNYzPyAEy6YBRThAA

I'd love to have someone else chime in here, but you can declare it separately from your code if needed...
````js
/* @flow */
import React from 'react';

type Foo = {
foo: number;
}

type Bar = {
bar: number;
}

declare function hoc<
Props: {},
Komponent: Class>,

(Component: Komponent): Class>

class A extends React.Component {
props: Bar;
}

const B = hoc(A)

const C = () =>
````

This was my puzzle for the evening, thank you. 馃槂

My solution:
````js
/* @flow */
import React from 'react';

type Foo = {
foo: number;
}

type Bar = {
bar: number;
}

type __UnwrapType> = T
type UnwrapType = __UnwrapType<*, T>

type ReactComponentClass>

function hoc<
T: Foo,
Component: ReactComponentClass<*>

(WrappedComponent: Component): ReactComponentClass & T> {
return class Enhancer extends WrappedComponent {
props: T
}
}

class A extends React.Component {
props: Bar
}

const B = hoc(A);

const C = () =>
````

@mwalkerwells Thanks!!!

Curious if this works for your use case...

Close?

This works.

/* @flow */
import React from 'react';

type Foo = {
  +foo: number;
}

type Bar = {
  +bar: number; 
}

function hoc<D, P, C: React$Component<D, P, void>>(
  component: Class<C>
): Class<React$Component<D, P & Foo, void>> {
  return class Enhancer extends WrappedComponent {
    props: P & Foo;
  }
}

class A extends React.Component {
  props: Bar;
}

const B = hoc(A);

const C = () => <B foo={1} bar={2}/>;

@nmn Awsome!! 馃憤

@nmn What is your definition for WrappedComponent?

js 18: return class Enhancer extends WrappedComponent { ^ identifier `WrappedComponent`. Could not resolve name

@mwalkerwells WrappedComponent just comes from the original example given here. Disregard it.

Was this page helpful?
0 / 5 - 0 ratings