A popular pattern in React is the higher-order component pattern, so it’s
important that we can provide effective types for higher-order components in
Flow. If you don’t already know what a higher-order component is then make sure
to read the React documentation on higher-order components before
continuing.
In 0.89.0, we introduced React.AbstractComponent
, which
gives you more expressive power when writing HOCs and library definitions.
Let’s take a look at how you can type some example HOCs.
The Trivial HOC
Let’s start with the simplest HOC:
1
2
3
4
5
6
7
8
|
import * as React from 'react';
function trivialHOC<Config: {}>(
Component: React.AbstractComponent<Config>
): React.AbstractComponent<Config> {
return Component;
}
|
{"value":"//@flow\nimport * as React from 'react';\n\nfunction trivialHOC<Config: {}>(\n Component: React.AbstractComponent<Config>\n): React.AbstractComponent<Config> {\n return Component;\n}\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_FUNCTION","context":"normal","value":"function","line":4,"start":41,"end":49},{"type":"T_IDENTIFIER","context":"normal","value":"trivialHOC","line":4,"start":50,"end":60},{"type":"T_LESS_THAN","context":"type","value":"<","line":4,"start":60,"end":61},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":4,"start":61,"end":67},{"type":"T_COLON","context":"type","value":":","line":4,"start":67,"end":68},{"type":"T_LCURLY","context":"type","value":"{","line":4,"start":69,"end":70},{"type":"T_RCURLY","context":"type","value":"}","line":4,"start":70,"end":71},{"type":"T_GREATER_THAN","context":"type","value":">","line":4,"start":71,"end":72},{"type":"T_LPAREN","context":"normal","value":"(","line":4,"start":72,"end":73},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":5,"start":76,"end":85},{"type":"T_COLON","context":"type","value":":","line":5,"start":85,"end":86},{"type":"T_IDENTIFIER","context":"type","value":"React","line":5,"start":87,"end":92},{"type":"T_PERIOD","context":"type","value":".","line":5,"start":92,"end":93},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":5,"start":93,"end":110},{"type":"T_LESS_THAN","context":"type","value":"<","line":5,"start":110,"end":111},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":5,"start":111,"end":117},{"type":"T_GREATER_THAN","context":"type","value":">","line":5,"start":117,"end":118},{"type":"T_RPAREN","context":"normal","value":")","line":6,"start":119,"end":120},{"type":"T_COLON","context":"type","value":":","line":6,"start":120,"end":121},{"type":"T_IDENTIFIER","context":"type","value":"React","line":6,"start":122,"end":127},{"type":"T_PERIOD","context":"type","value":".","line":6,"start":127,"end":128},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":6,"start":128,"end":145},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":145,"end":146},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":146,"end":152},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":152,"end":153},{"type":"T_LCURLY","context":"normal","value":"{","line":6,"start":154,"end":155},{"type":"T_RETURN","context":"normal","value":"return","line":7,"start":158,"end":164},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":165,"end":174},{"type":"T_SEMICOLON","context":"normal","value":";","line":7,"start":174,"end":175},{"type":"T_RCURLY","context":"normal","value":"}","line":8,"start":176,"end":177}],"errors":[]}
This is a basic template for what your HOCs might look like. At runtime, this HOC doesn’t
do anything at all. Let’s take a look at some more complex examples.
Injecting Props
A common use case for higher-order components is to inject a prop.
The HOC automatically sets a prop and returns a component which no longer requires
that prop. For example, consider a navigation prop, or in the case of
react-redux
a store
prop. How would one type this?
To remove a prop from the config, we can take a component that includes the
prop and return a component that does not. It’s best to construct these
types using object type spread.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import * as React from 'react';
type InjectedProps = {| foo: number |}
function injectProp<Config>(
Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}>
): React.AbstractComponent<Config> {
return function WrapperComponent(
props: Config,
) {
return <Component {...props} foo={42} />;
};
}
class MyComponent extends React.Component<{|
a: number,
b: number,
...InjectedProps,
|}> {}
const MyEnhancedComponent = injectProp(MyComponent);
<MyEnhancedComponent a={1} b={2} />;
|
{"value":"//@flow\nimport * as React from 'react';\n\ntype InjectedProps = {| foo: number |}\n\nfunction injectProp<Config>(\n Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}>\n): React.AbstractComponent<Config> {\n return function WrapperComponent(\n props: Config,\n ) {\n return <Component {...props} foo={42} />;\n };\n}\n\nclass MyComponent extends React.Component<{|\n a: number,\n b: number,\n ...InjectedProps,\n|}> {}\n\nconst MyEnhancedComponent = injectProp(MyComponent);\n\n// We don't need to pass in `foo` even though `MyComponent` requires it.\n<MyEnhancedComponent a={1} b={2} />;\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_TYPE","context":"normal","value":"type","line":4,"start":41,"end":45},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":4,"start":46,"end":59},{"type":"T_ASSIGN","context":"type","value":"=","line":4,"start":60,"end":61},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":4,"start":62,"end":64},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":4,"start":65,"end":68},{"type":"T_COLON","context":"type","value":":","line":4,"start":68,"end":69},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":70,"end":76},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":4,"start":77,"end":79},{"type":"T_FUNCTION","context":"normal","value":"function","line":6,"start":81,"end":89},{"type":"T_IDENTIFIER","context":"normal","value":"injectProp","line":6,"start":90,"end":100},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":100,"end":101},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":101,"end":107},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":107,"end":108},{"type":"T_LPAREN","context":"normal","value":"(","line":6,"start":108,"end":109},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":112,"end":121},{"type":"T_COLON","context":"type","value":":","line":7,"start":121,"end":122},{"type":"T_IDENTIFIER","context":"type","value":"React","line":7,"start":123,"end":128},{"type":"T_PERIOD","context":"type","value":".","line":7,"start":128,"end":129},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":7,"start":129,"end":146},{"type":"T_LESS_THAN","context":"type","value":"<","line":7,"start":146,"end":147},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":7,"start":147,"end":149},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":150,"end":153},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":7,"start":153,"end":159},{"type":"T_COMMA","context":"type","value":",","line":7,"start":159,"end":160},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":161,"end":164},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":7,"start":164,"end":177},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":7,"start":178,"end":180},{"type":"T_GREATER_THAN","context":"type","value":">","line":7,"start":180,"end":181},{"type":"T_RPAREN","context":"normal","value":")","line":8,"start":182,"end":183},{"type":"T_COLON","context":"type","value":":","line":8,"start":183,"end":184},{"type":"T_IDENTIFIER","context":"type","value":"React","line":8,"start":185,"end":190},{"type":"T_PERIOD","context":"type","value":".","line":8,"start":190,"end":191},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":8,"start":191,"end":208},{"type":"T_LESS_THAN","context":"type","value":"<","line":8,"start":208,"end":209},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":8,"start":209,"end":215},{"type":"T_GREATER_THAN","context":"type","value":">","line":8,"start":215,"end":216},{"type":"T_LCURLY","context":"normal","value":"{","line":8,"start":217,"end":218},{"type":"T_RETURN","context":"normal","value":"return","line":9,"start":221,"end":227},{"type":"T_FUNCTION","context":"normal","value":"function","line":9,"start":228,"end":236},{"type":"T_IDENTIFIER","context":"normal","value":"WrapperComponent","line":9,"start":237,"end":253},{"type":"T_LPAREN","context":"normal","value":"(","line":9,"start":253,"end":254},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":10,"start":259,"end":264},{"type":"T_COLON","context":"type","value":":","line":10,"start":264,"end":265},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":10,"start":266,"end":272},{"type":"T_COMMA","context":"normal","value":",","line":10,"start":272,"end":273},{"type":"T_RPAREN","context":"normal","value":")","line":11,"start":276,"end":277},{"type":"T_LCURLY","context":"normal","value":"{","line":11,"start":278,"end":279},{"type":"T_RETURN","context":"normal","value":"return","line":12,"start":284,"end":290},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":12,"start":291,"end":292},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"Component","line":12,"start":292,"end":301},{"type":"T_LCURLY","context":"normal","value":"{","line":12,"start":302,"end":303},{"type":"T_ELLIPSIS","context":"normal","value":"...","line":12,"start":303,"end":306},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":12,"start":306,"end":311},{"type":"T_RCURLY","context":"normal","value":"}","line":12,"start":311,"end":312},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"foo","line":12,"start":313,"end":316},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":12,"start":316,"end":317},{"type":"T_LCURLY","context":"normal","value":"{","line":12,"start":317,"end":318},{"type":"T_NUMBER","context":"normal","value":"42","line":12,"start":318,"end":320},{"type":"T_RCURLY","context":"normal","value":"}","line":12,"start":320,"end":321},{"type":"T_DIV","context":"jsxTag","value":"/","line":12,"start":322,"end":323},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":12,"start":323,"end":324},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":324,"end":325},{"type":"T_RCURLY","context":"normal","value":"}","line":13,"start":328,"end":329},{"type":"T_SEMICOLON","context":"normal","value":";","line":13,"start":329,"end":330},{"type":"T_RCURLY","context":"normal","value":"}","line":14,"start":331,"end":332},{"type":"T_CLASS","context":"normal","value":"class","line":16,"start":334,"end":339},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":16,"start":340,"end":351},{"type":"T_EXTENDS","context":"normal","value":"extends","line":16,"start":352,"end":359},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":16,"start":360,"end":365},{"type":"T_PERIOD","context":"normal","value":".","line":16,"start":365,"end":366},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":16,"start":366,"end":375},{"type":"T_LESS_THAN","context":"type","value":"<","line":16,"start":375,"end":376},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":16,"start":376,"end":378},{"type":"T_IDENTIFIER","context":"normal","value":"a","line":17,"start":381,"end":382},{"type":"T_COLON","context":"type","value":":","line":17,"start":382,"end":383},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":17,"start":384,"end":390},{"type":"T_COMMA","context":"type","value":",","line":17,"start":390,"end":391},{"type":"T_IDENTIFIER","context":"normal","value":"b","line":18,"start":394,"end":395},{"type":"T_COLON","context":"type","value":":","line":18,"start":395,"end":396},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":18,"start":397,"end":403},{"type":"T_COMMA","context":"type","value":",","line":18,"start":403,"end":404},{"type":"T_ELLIPSIS","context":"type","value":"...","line":19,"start":407,"end":410},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":19,"start":410,"end":423},{"type":"T_COMMA","context":"type","value":",","line":19,"start":423,"end":424},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":20,"start":425,"end":427},{"type":"T_GREATER_THAN","context":"type","value":">","line":20,"start":427,"end":428},{"type":"T_LCURLY","context":"normal","value":"{","line":20,"start":429,"end":430},{"type":"T_RCURLY","context":"normal","value":"}","line":20,"start":430,"end":431},{"type":"T_CONST","context":"normal","value":"const","line":22,"start":433,"end":438},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":22,"start":439,"end":458},{"type":"T_ASSIGN","context":"normal","value":"=","line":22,"start":459,"end":460},{"type":"T_IDENTIFIER","context":"normal","value":"injectProp","line":22,"start":461,"end":471},{"type":"T_LPAREN","context":"normal","value":"(","line":22,"start":471,"end":472},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":22,"start":472,"end":483},{"type":"T_RPAREN","context":"normal","value":")","line":22,"start":483,"end":484},{"type":"T_SEMICOLON","context":"normal","value":";","line":22,"start":484,"end":485},{"type":"Line","context":"comment","value":"// We don't need to pass in `foo` even though `MyComponent` requires it.","line":24,"start":487,"end":559},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":25,"start":560,"end":561},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"MyEnhancedComponent","line":25,"start":561,"end":580},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"a","line":25,"start":581,"end":582},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":25,"start":582,"end":583},{"type":"T_LCURLY","context":"normal","value":"{","line":25,"start":583,"end":584},{"type":"T_NUMBER","context":"normal","value":"1","line":25,"start":584,"end":585},{"type":"T_RCURLY","context":"normal","value":"}","line":25,"start":585,"end":586},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"b","line":25,"start":587,"end":588},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":25,"start":588,"end":589},{"type":"T_LCURLY","context":"normal","value":"{","line":25,"start":589,"end":590},{"type":"T_NUMBER","context":"normal","value":"2","line":25,"start":590,"end":591},{"type":"T_RCURLY","context":"normal","value":"}","line":25,"start":591,"end":592},{"type":"T_DIV","context":"jsxTag","value":"/","line":25,"start":593,"end":594},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":25,"start":594,"end":595},{"type":"T_SEMICOLON","context":"normal","value":";","line":25,"start":595,"end":596}],"errors":[]}
Preserving the Instance Type of a Component
Recall that the instance type of a function component is void
. Our example
above wraps a component in a function, so the returned component has the instance
type void
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import * as React from 'react';
type InjectedProps = {| foo: number |}
function injectProp<Config>(
Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}>
): React.AbstractComponent<Config> {
return function WrapperComponent(
props: Config,
) {
return <Component {...props} foo={42} />;
};
}
class MyComponent extends React.Component<{|
a: number,
b: number,
...InjectedProps,
|}> {}
const MyEnhancedComponent = injectProp(MyComponent);
const ref = React.createRef<MyComponent>();
<MyEnhancedComponent ref={ref} a={1} b={2} />;
|
Cannot create `MyEnhancedComponent` element because in property `ref`: [incompatible-type] Either mixed [1] is incompatible with `MyComponent` [2] in property `current`. Or a call signature declaring the expected parameter / return type is missing in object type [3] but exists in function type [4].
{"value":"//@flow\nimport * as React from 'react';\n\ntype InjectedProps = {| foo: number |}\n\nfunction injectProp<Config>(\n Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}>\n): React.AbstractComponent<Config> {\n return function WrapperComponent(\n props: Config,\n ) {\n return <Component {...props} foo={42} />;\n };\n}\n\nclass MyComponent extends React.Component<{|\n a: number,\n b: number,\n ...InjectedProps,\n|}> {}\n\nconst MyEnhancedComponent = injectProp(MyComponent);\n\n// If we create a ref object for the component, it will never be assigned\n// an instance of MyComponent!\nconst ref = React.createRef<MyComponent>();\n\n// Error, mixed is incompatible with MyComponent.\n<MyEnhancedComponent ref={ref} a={1} b={2} />;\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_TYPE","context":"normal","value":"type","line":4,"start":41,"end":45},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":4,"start":46,"end":59},{"type":"T_ASSIGN","context":"type","value":"=","line":4,"start":60,"end":61},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":4,"start":62,"end":64},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":4,"start":65,"end":68},{"type":"T_COLON","context":"type","value":":","line":4,"start":68,"end":69},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":70,"end":76},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":4,"start":77,"end":79},{"type":"T_FUNCTION","context":"normal","value":"function","line":6,"start":81,"end":89},{"type":"T_IDENTIFIER","context":"normal","value":"injectProp","line":6,"start":90,"end":100},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":100,"end":101},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":101,"end":107},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":107,"end":108},{"type":"T_LPAREN","context":"normal","value":"(","line":6,"start":108,"end":109},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":112,"end":121},{"type":"T_COLON","context":"type","value":":","line":7,"start":121,"end":122},{"type":"T_IDENTIFIER","context":"type","value":"React","line":7,"start":123,"end":128},{"type":"T_PERIOD","context":"type","value":".","line":7,"start":128,"end":129},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":7,"start":129,"end":146},{"type":"T_LESS_THAN","context":"type","value":"<","line":7,"start":146,"end":147},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":7,"start":147,"end":149},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":150,"end":153},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":7,"start":153,"end":159},{"type":"T_COMMA","context":"type","value":",","line":7,"start":159,"end":160},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":161,"end":164},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":7,"start":164,"end":177},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":7,"start":178,"end":180},{"type":"T_GREATER_THAN","context":"type","value":">","line":7,"start":180,"end":181},{"type":"T_RPAREN","context":"normal","value":")","line":8,"start":182,"end":183},{"type":"T_COLON","context":"type","value":":","line":8,"start":183,"end":184},{"type":"T_IDENTIFIER","context":"type","value":"React","line":8,"start":185,"end":190},{"type":"T_PERIOD","context":"type","value":".","line":8,"start":190,"end":191},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":8,"start":191,"end":208},{"type":"T_LESS_THAN","context":"type","value":"<","line":8,"start":208,"end":209},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":8,"start":209,"end":215},{"type":"T_GREATER_THAN","context":"type","value":">","line":8,"start":215,"end":216},{"type":"T_LCURLY","context":"normal","value":"{","line":8,"start":217,"end":218},{"type":"T_RETURN","context":"normal","value":"return","line":9,"start":221,"end":227},{"type":"T_FUNCTION","context":"normal","value":"function","line":9,"start":228,"end":236},{"type":"T_IDENTIFIER","context":"normal","value":"WrapperComponent","line":9,"start":237,"end":253},{"type":"T_LPAREN","context":"normal","value":"(","line":9,"start":253,"end":254},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":10,"start":259,"end":264},{"type":"T_COLON","context":"type","value":":","line":10,"start":264,"end":265},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":10,"start":266,"end":272},{"type":"T_COMMA","context":"normal","value":",","line":10,"start":272,"end":273},{"type":"T_RPAREN","context":"normal","value":")","line":11,"start":276,"end":277},{"type":"T_LCURLY","context":"normal","value":"{","line":11,"start":278,"end":279},{"type":"T_RETURN","context":"normal","value":"return","line":12,"start":284,"end":290},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":12,"start":291,"end":292},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"Component","line":12,"start":292,"end":301},{"type":"T_LCURLY","context":"normal","value":"{","line":12,"start":302,"end":303},{"type":"T_ELLIPSIS","context":"normal","value":"...","line":12,"start":303,"end":306},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":12,"start":306,"end":311},{"type":"T_RCURLY","context":"normal","value":"}","line":12,"start":311,"end":312},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"foo","line":12,"start":313,"end":316},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":12,"start":316,"end":317},{"type":"T_LCURLY","context":"normal","value":"{","line":12,"start":317,"end":318},{"type":"T_NUMBER","context":"normal","value":"42","line":12,"start":318,"end":320},{"type":"T_RCURLY","context":"normal","value":"}","line":12,"start":320,"end":321},{"type":"T_DIV","context":"jsxTag","value":"/","line":12,"start":322,"end":323},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":12,"start":323,"end":324},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":324,"end":325},{"type":"T_RCURLY","context":"normal","value":"}","line":13,"start":328,"end":329},{"type":"T_SEMICOLON","context":"normal","value":";","line":13,"start":329,"end":330},{"type":"T_RCURLY","context":"normal","value":"}","line":14,"start":331,"end":332},{"type":"T_CLASS","context":"normal","value":"class","line":16,"start":334,"end":339},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":16,"start":340,"end":351},{"type":"T_EXTENDS","context":"normal","value":"extends","line":16,"start":352,"end":359},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":16,"start":360,"end":365},{"type":"T_PERIOD","context":"normal","value":".","line":16,"start":365,"end":366},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":16,"start":366,"end":375},{"type":"T_LESS_THAN","context":"type","value":"<","line":16,"start":375,"end":376},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":16,"start":376,"end":378},{"type":"T_IDENTIFIER","context":"normal","value":"a","line":17,"start":381,"end":382},{"type":"T_COLON","context":"type","value":":","line":17,"start":382,"end":383},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":17,"start":384,"end":390},{"type":"T_COMMA","context":"type","value":",","line":17,"start":390,"end":391},{"type":"T_IDENTIFIER","context":"normal","value":"b","line":18,"start":394,"end":395},{"type":"T_COLON","context":"type","value":":","line":18,"start":395,"end":396},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":18,"start":397,"end":403},{"type":"T_COMMA","context":"type","value":",","line":18,"start":403,"end":404},{"type":"T_ELLIPSIS","context":"type","value":"...","line":19,"start":407,"end":410},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":19,"start":410,"end":423},{"type":"T_COMMA","context":"type","value":",","line":19,"start":423,"end":424},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":20,"start":425,"end":427},{"type":"T_GREATER_THAN","context":"type","value":">","line":20,"start":427,"end":428},{"type":"T_LCURLY","context":"normal","value":"{","line":20,"start":429,"end":430},{"type":"T_RCURLY","context":"normal","value":"}","line":20,"start":430,"end":431},{"type":"T_CONST","context":"normal","value":"const","line":22,"start":433,"end":438},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":22,"start":439,"end":458},{"type":"T_ASSIGN","context":"normal","value":"=","line":22,"start":459,"end":460},{"type":"T_IDENTIFIER","context":"normal","value":"injectProp","line":22,"start":461,"end":471},{"type":"T_LPAREN","context":"normal","value":"(","line":22,"start":471,"end":472},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":22,"start":472,"end":483},{"type":"T_RPAREN","context":"normal","value":")","line":22,"start":483,"end":484},{"type":"T_SEMICOLON","context":"normal","value":";","line":22,"start":484,"end":485},{"type":"Line","context":"comment","value":"// If we create a ref object for the component, it will never be assigned","line":24,"start":487,"end":560},{"type":"Line","context":"comment","value":"// an instance of MyComponent!","line":25,"start":561,"end":591},{"type":"T_CONST","context":"normal","value":"const","line":26,"start":592,"end":597},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":26,"start":598,"end":601},{"type":"T_ASSIGN","context":"normal","value":"=","line":26,"start":602,"end":603},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":26,"start":604,"end":609},{"type":"T_PERIOD","context":"normal","value":".","line":26,"start":609,"end":610},{"type":"T_IDENTIFIER","context":"normal","value":"createRef","line":26,"start":610,"end":619},{"type":"T_LESS_THAN","context":"type","value":"<","line":26,"start":619,"end":620},{"type":"T_IDENTIFIER","context":"type","value":"MyComponent","line":26,"start":620,"end":631},{"type":"T_GREATER_THAN","context":"type","value":">","line":26,"start":631,"end":632},{"type":"T_LPAREN","context":"normal","value":"(","line":26,"start":632,"end":633},{"type":"T_RPAREN","context":"normal","value":")","line":26,"start":633,"end":634},{"type":"T_SEMICOLON","context":"normal","value":";","line":26,"start":634,"end":635},{"type":"Line","context":"comment","value":"// Error, mixed is incompatible with MyComponent.","line":28,"start":637,"end":686},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":29,"start":687,"end":688},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"MyEnhancedComponent","line":29,"start":688,"end":707},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"ref","line":29,"start":708,"end":711},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":29,"start":711,"end":712},{"type":"T_LCURLY","context":"normal","value":"{","line":29,"start":712,"end":713},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":29,"start":713,"end":716},{"type":"T_RCURLY","context":"normal","value":"}","line":29,"start":716,"end":717},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"a","line":29,"start":718,"end":719},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":29,"start":719,"end":720},{"type":"T_LCURLY","context":"normal","value":"{","line":29,"start":720,"end":721},{"type":"T_NUMBER","context":"normal","value":"1","line":29,"start":721,"end":722},{"type":"T_RCURLY","context":"normal","value":"}","line":29,"start":722,"end":723},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"b","line":29,"start":724,"end":725},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":29,"start":725,"end":726},{"type":"T_LCURLY","context":"normal","value":"{","line":29,"start":726,"end":727},{"type":"T_NUMBER","context":"normal","value":"2","line":29,"start":727,"end":728},{"type":"T_RCURLY","context":"normal","value":"}","line":29,"start":728,"end":729},{"type":"T_DIV","context":"jsxTag","value":"/","line":29,"start":730,"end":731},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":29,"start":731,"end":732},{"type":"T_SEMICOLON","context":"normal","value":";","line":29,"start":732,"end":733}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot create `MyEnhancedComponent` element because in property `ref`: [incompatible-type] Either mixed [1] is incompatible with `MyComponent` [2] in property `current`. Or a call signature declaring the expected parameter / return type is missing in object type [3] but exists in function type [4].","context":"<MyEnhancedComponent ref={ref} a={1} b={2} />;","source":"-","start":{"line":29,"column":27,"offset":713},"end":{"line":29,"column":29,"offset":716}}],"operation":null}]}
We get this error message because React.AbstractComponent<Config>
doesn’t set the Instance
type
parameter, so it is automatically set to mixed
. If we wanted to preserve the instance type
of the component, we can use React.forwardRef
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import * as React from 'react';
type InjectedProps = {| foo: number |}
function injectAndPreserveInstance<Config, Instance>(
Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}, Instance>
): React.AbstractComponent<Config, Instance> {
return React.forwardRef<Config, Instance>((props, ref) =>
<Component ref={ref} foo={3} {...props} />
);
}
class MyComponent extends React.Component<{
a: number,
b: number,
...InjectedProps,
}> {}
const MyEnhancedComponent = injectAndPreserveInstance(MyComponent);
const ref = React.createRef<MyComponent>();
<MyEnhancedComponent ref={ref} a={1} b={2} />;
|
{"value":"//@flow\nimport * as React from 'react';\n\ntype InjectedProps = {| foo: number |}\n\nfunction injectAndPreserveInstance<Config, Instance>(\n Component: React.AbstractComponent<{| ...Config, ...InjectedProps |}, Instance>\n): React.AbstractComponent<Config, Instance> {\n return React.forwardRef<Config, Instance>((props, ref) =>\n <Component ref={ref} foo={3} {...props} />\n );\n}\n\nclass MyComponent extends React.Component<{\n a: number,\n b: number,\n ...InjectedProps,\n}> {}\n\nconst MyEnhancedComponent = injectAndPreserveInstance(MyComponent);\n\nconst ref = React.createRef<MyComponent>();\n\n// All good! The ref is forwarded.\n<MyEnhancedComponent ref={ref} a={1} b={2} />;\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_TYPE","context":"normal","value":"type","line":4,"start":41,"end":45},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":4,"start":46,"end":59},{"type":"T_ASSIGN","context":"type","value":"=","line":4,"start":60,"end":61},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":4,"start":62,"end":64},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":4,"start":65,"end":68},{"type":"T_COLON","context":"type","value":":","line":4,"start":68,"end":69},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":70,"end":76},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":4,"start":77,"end":79},{"type":"T_FUNCTION","context":"normal","value":"function","line":6,"start":81,"end":89},{"type":"T_IDENTIFIER","context":"normal","value":"injectAndPreserveInstance","line":6,"start":90,"end":115},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":115,"end":116},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":116,"end":122},{"type":"T_COMMA","context":"type","value":",","line":6,"start":122,"end":123},{"type":"T_IDENTIFIER","context":"type","value":"Instance","line":6,"start":124,"end":132},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":132,"end":133},{"type":"T_LPAREN","context":"normal","value":"(","line":6,"start":133,"end":134},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":137,"end":146},{"type":"T_COLON","context":"type","value":":","line":7,"start":146,"end":147},{"type":"T_IDENTIFIER","context":"type","value":"React","line":7,"start":148,"end":153},{"type":"T_PERIOD","context":"type","value":".","line":7,"start":153,"end":154},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":7,"start":154,"end":171},{"type":"T_LESS_THAN","context":"type","value":"<","line":7,"start":171,"end":172},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":7,"start":172,"end":174},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":175,"end":178},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":7,"start":178,"end":184},{"type":"T_COMMA","context":"type","value":",","line":7,"start":184,"end":185},{"type":"T_ELLIPSIS","context":"type","value":"...","line":7,"start":186,"end":189},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":7,"start":189,"end":202},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":7,"start":203,"end":205},{"type":"T_COMMA","context":"type","value":",","line":7,"start":205,"end":206},{"type":"T_IDENTIFIER","context":"type","value":"Instance","line":7,"start":207,"end":215},{"type":"T_GREATER_THAN","context":"type","value":">","line":7,"start":215,"end":216},{"type":"T_RPAREN","context":"normal","value":")","line":8,"start":217,"end":218},{"type":"T_COLON","context":"type","value":":","line":8,"start":218,"end":219},{"type":"T_IDENTIFIER","context":"type","value":"React","line":8,"start":220,"end":225},{"type":"T_PERIOD","context":"type","value":".","line":8,"start":225,"end":226},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":8,"start":226,"end":243},{"type":"T_LESS_THAN","context":"type","value":"<","line":8,"start":243,"end":244},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":8,"start":244,"end":250},{"type":"T_COMMA","context":"type","value":",","line":8,"start":250,"end":251},{"type":"T_IDENTIFIER","context":"type","value":"Instance","line":8,"start":252,"end":260},{"type":"T_GREATER_THAN","context":"type","value":">","line":8,"start":260,"end":261},{"type":"T_LCURLY","context":"normal","value":"{","line":8,"start":262,"end":263},{"type":"T_RETURN","context":"normal","value":"return","line":9,"start":266,"end":272},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":9,"start":273,"end":278},{"type":"T_PERIOD","context":"normal","value":".","line":9,"start":278,"end":279},{"type":"T_IDENTIFIER","context":"normal","value":"forwardRef","line":9,"start":279,"end":289},{"type":"T_LESS_THAN","context":"type","value":"<","line":9,"start":289,"end":290},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":9,"start":290,"end":296},{"type":"T_COMMA","context":"type","value":",","line":9,"start":296,"end":297},{"type":"T_IDENTIFIER","context":"type","value":"Instance","line":9,"start":298,"end":306},{"type":"T_GREATER_THAN","context":"type","value":">","line":9,"start":306,"end":307},{"type":"T_LPAREN","context":"normal","value":"(","line":9,"start":307,"end":308},{"type":"T_LPAREN","context":"normal","value":"(","line":9,"start":308,"end":309},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":9,"start":309,"end":314},{"type":"T_COMMA","context":"normal","value":",","line":9,"start":314,"end":315},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":9,"start":316,"end":319},{"type":"T_RPAREN","context":"normal","value":")","line":9,"start":319,"end":320},{"type":"T_ARROW","context":"normal","value":"=>","line":9,"start":321,"end":323},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":10,"start":330,"end":331},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"Component","line":10,"start":331,"end":340},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"ref","line":10,"start":341,"end":344},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":10,"start":344,"end":345},{"type":"T_LCURLY","context":"normal","value":"{","line":10,"start":345,"end":346},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":10,"start":346,"end":349},{"type":"T_RCURLY","context":"normal","value":"}","line":10,"start":349,"end":350},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"foo","line":10,"start":351,"end":354},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":10,"start":354,"end":355},{"type":"T_LCURLY","context":"normal","value":"{","line":10,"start":355,"end":356},{"type":"T_NUMBER","context":"normal","value":"3","line":10,"start":356,"end":357},{"type":"T_RCURLY","context":"normal","value":"}","line":10,"start":357,"end":358},{"type":"T_LCURLY","context":"normal","value":"{","line":10,"start":359,"end":360},{"type":"T_ELLIPSIS","context":"normal","value":"...","line":10,"start":360,"end":363},{"type":"T_IDENTIFIER","context":"normal","value":"props","line":10,"start":363,"end":368},{"type":"T_RCURLY","context":"normal","value":"}","line":10,"start":368,"end":369},{"type":"T_DIV","context":"jsxTag","value":"/","line":10,"start":370,"end":371},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":10,"start":371,"end":372},{"type":"T_RPAREN","context":"normal","value":")","line":11,"start":375,"end":376},{"type":"T_SEMICOLON","context":"normal","value":";","line":11,"start":376,"end":377},{"type":"T_RCURLY","context":"normal","value":"}","line":12,"start":378,"end":379},{"type":"T_CLASS","context":"normal","value":"class","line":14,"start":381,"end":386},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":14,"start":387,"end":398},{"type":"T_EXTENDS","context":"normal","value":"extends","line":14,"start":399,"end":406},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":14,"start":407,"end":412},{"type":"T_PERIOD","context":"normal","value":".","line":14,"start":412,"end":413},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":14,"start":413,"end":422},{"type":"T_LESS_THAN","context":"type","value":"<","line":14,"start":422,"end":423},{"type":"T_LCURLY","context":"type","value":"{","line":14,"start":423,"end":424},{"type":"T_IDENTIFIER","context":"normal","value":"a","line":15,"start":427,"end":428},{"type":"T_COLON","context":"type","value":":","line":15,"start":428,"end":429},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":15,"start":430,"end":436},{"type":"T_COMMA","context":"type","value":",","line":15,"start":436,"end":437},{"type":"T_IDENTIFIER","context":"normal","value":"b","line":16,"start":440,"end":441},{"type":"T_COLON","context":"type","value":":","line":16,"start":441,"end":442},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":16,"start":443,"end":449},{"type":"T_COMMA","context":"type","value":",","line":16,"start":449,"end":450},{"type":"T_ELLIPSIS","context":"type","value":"...","line":17,"start":453,"end":456},{"type":"T_IDENTIFIER","context":"type","value":"InjectedProps","line":17,"start":456,"end":469},{"type":"T_COMMA","context":"type","value":",","line":17,"start":469,"end":470},{"type":"T_RCURLY","context":"type","value":"}","line":18,"start":471,"end":472},{"type":"T_GREATER_THAN","context":"type","value":">","line":18,"start":472,"end":473},{"type":"T_LCURLY","context":"normal","value":"{","line":18,"start":474,"end":475},{"type":"T_RCURLY","context":"normal","value":"}","line":18,"start":475,"end":476},{"type":"T_CONST","context":"normal","value":"const","line":20,"start":478,"end":483},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":20,"start":484,"end":503},{"type":"T_ASSIGN","context":"normal","value":"=","line":20,"start":504,"end":505},{"type":"T_IDENTIFIER","context":"normal","value":"injectAndPreserveInstance","line":20,"start":506,"end":531},{"type":"T_LPAREN","context":"normal","value":"(","line":20,"start":531,"end":532},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":20,"start":532,"end":543},{"type":"T_RPAREN","context":"normal","value":")","line":20,"start":543,"end":544},{"type":"T_SEMICOLON","context":"normal","value":";","line":20,"start":544,"end":545},{"type":"T_CONST","context":"normal","value":"const","line":22,"start":547,"end":552},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":22,"start":553,"end":556},{"type":"T_ASSIGN","context":"normal","value":"=","line":22,"start":557,"end":558},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":22,"start":559,"end":564},{"type":"T_PERIOD","context":"normal","value":".","line":22,"start":564,"end":565},{"type":"T_IDENTIFIER","context":"normal","value":"createRef","line":22,"start":565,"end":574},{"type":"T_LESS_THAN","context":"type","value":"<","line":22,"start":574,"end":575},{"type":"T_IDENTIFIER","context":"type","value":"MyComponent","line":22,"start":575,"end":586},{"type":"T_GREATER_THAN","context":"type","value":">","line":22,"start":586,"end":587},{"type":"T_LPAREN","context":"normal","value":"(","line":22,"start":587,"end":588},{"type":"T_RPAREN","context":"normal","value":")","line":22,"start":588,"end":589},{"type":"T_SEMICOLON","context":"normal","value":";","line":22,"start":589,"end":590},{"type":"Line","context":"comment","value":"// All good! The ref is forwarded.","line":24,"start":592,"end":626},{"type":"T_LESS_THAN","context":"jsxTag","value":"<","line":25,"start":627,"end":628},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"MyEnhancedComponent","line":25,"start":628,"end":647},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"ref","line":25,"start":648,"end":651},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":25,"start":651,"end":652},{"type":"T_LCURLY","context":"normal","value":"{","line":25,"start":652,"end":653},{"type":"T_IDENTIFIER","context":"normal","value":"ref","line":25,"start":653,"end":656},{"type":"T_RCURLY","context":"normal","value":"}","line":25,"start":656,"end":657},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"a","line":25,"start":658,"end":659},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":25,"start":659,"end":660},{"type":"T_LCURLY","context":"normal","value":"{","line":25,"start":660,"end":661},{"type":"T_NUMBER","context":"normal","value":"1","line":25,"start":661,"end":662},{"type":"T_RCURLY","context":"normal","value":"}","line":25,"start":662,"end":663},{"type":"T_JSX_IDENTIFIER","context":"jsxTag","value":"b","line":25,"start":664,"end":665},{"type":"T_ASSIGN","context":"jsxTag","value":"=","line":25,"start":665,"end":666},{"type":"T_LCURLY","context":"normal","value":"{","line":25,"start":666,"end":667},{"type":"T_NUMBER","context":"normal","value":"2","line":25,"start":667,"end":668},{"type":"T_RCURLY","context":"normal","value":"}","line":25,"start":668,"end":669},{"type":"T_DIV","context":"jsxTag","value":"/","line":25,"start":670,"end":671},{"type":"T_GREATER_THAN","context":"jsxTag","value":">","line":25,"start":671,"end":672},{"type":"T_SEMICOLON","context":"normal","value":";","line":25,"start":672,"end":673}],"errors":[]}
Exporting Wrapped Components
If you try to export a wrapped component, chances are that you’ll run into a missing annotation error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import * as React from 'react';
function trivialHOC<Config: {}>(
Component: React.AbstractComponent<Config>,
): React.AbstractComponent<Config> {
return Component;
}
type DefaultProps = {| foo: number |};
type Props = {...DefaultProps, bar: number};
class MyComponent extends React.Component<Props> {
static defaultProps: DefaultProps = {foo: 3};
}
const MyEnhancedComponent = trivialHOC(MyComponent);
module.exports = MyEnhancedComponent;
|
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. [signature-verification-failure]
{"value":"//@flow\nimport * as React from 'react';\n\nfunction trivialHOC<Config: {}>(\n Component: React.AbstractComponent<Config>,\n): React.AbstractComponent<Config> {\n return Component;\n}\n\ntype DefaultProps = {| foo: number |};\ntype Props = {...DefaultProps, bar: number};\n\nclass MyComponent extends React.Component<Props> {\n static defaultProps: DefaultProps = {foo: 3};\n}\n\n// Error, missing annotation for Config.\nconst MyEnhancedComponent = trivialHOC(MyComponent);\n\nmodule.exports = MyEnhancedComponent;\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_FUNCTION","context":"normal","value":"function","line":4,"start":41,"end":49},{"type":"T_IDENTIFIER","context":"normal","value":"trivialHOC","line":4,"start":50,"end":60},{"type":"T_LESS_THAN","context":"type","value":"<","line":4,"start":60,"end":61},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":4,"start":61,"end":67},{"type":"T_COLON","context":"type","value":":","line":4,"start":67,"end":68},{"type":"T_LCURLY","context":"type","value":"{","line":4,"start":69,"end":70},{"type":"T_RCURLY","context":"type","value":"}","line":4,"start":70,"end":71},{"type":"T_GREATER_THAN","context":"type","value":">","line":4,"start":71,"end":72},{"type":"T_LPAREN","context":"normal","value":"(","line":4,"start":72,"end":73},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":5,"start":76,"end":85},{"type":"T_COLON","context":"type","value":":","line":5,"start":85,"end":86},{"type":"T_IDENTIFIER","context":"type","value":"React","line":5,"start":87,"end":92},{"type":"T_PERIOD","context":"type","value":".","line":5,"start":92,"end":93},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":5,"start":93,"end":110},{"type":"T_LESS_THAN","context":"type","value":"<","line":5,"start":110,"end":111},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":5,"start":111,"end":117},{"type":"T_GREATER_THAN","context":"type","value":">","line":5,"start":117,"end":118},{"type":"T_COMMA","context":"normal","value":",","line":5,"start":118,"end":119},{"type":"T_RPAREN","context":"normal","value":")","line":6,"start":120,"end":121},{"type":"T_COLON","context":"type","value":":","line":6,"start":121,"end":122},{"type":"T_IDENTIFIER","context":"type","value":"React","line":6,"start":123,"end":128},{"type":"T_PERIOD","context":"type","value":".","line":6,"start":128,"end":129},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":6,"start":129,"end":146},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":146,"end":147},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":147,"end":153},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":153,"end":154},{"type":"T_LCURLY","context":"normal","value":"{","line":6,"start":155,"end":156},{"type":"T_RETURN","context":"normal","value":"return","line":7,"start":159,"end":165},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":166,"end":175},{"type":"T_SEMICOLON","context":"normal","value":";","line":7,"start":175,"end":176},{"type":"T_RCURLY","context":"normal","value":"}","line":8,"start":177,"end":178},{"type":"T_TYPE","context":"normal","value":"type","line":10,"start":180,"end":184},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":10,"start":185,"end":197},{"type":"T_ASSIGN","context":"type","value":"=","line":10,"start":198,"end":199},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":10,"start":200,"end":202},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":10,"start":203,"end":206},{"type":"T_COLON","context":"type","value":":","line":10,"start":206,"end":207},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":10,"start":208,"end":214},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":10,"start":215,"end":217},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":217,"end":218},{"type":"T_TYPE","context":"normal","value":"type","line":11,"start":219,"end":223},{"type":"T_IDENTIFIER","context":"type","value":"Props","line":11,"start":224,"end":229},{"type":"T_ASSIGN","context":"type","value":"=","line":11,"start":230,"end":231},{"type":"T_LCURLY","context":"type","value":"{","line":11,"start":232,"end":233},{"type":"T_ELLIPSIS","context":"type","value":"...","line":11,"start":233,"end":236},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":11,"start":236,"end":248},{"type":"T_COMMA","context":"type","value":",","line":11,"start":248,"end":249},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":11,"start":250,"end":253},{"type":"T_COLON","context":"type","value":":","line":11,"start":253,"end":254},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":11,"start":255,"end":261},{"type":"T_RCURLY","context":"type","value":"}","line":11,"start":261,"end":262},{"type":"T_SEMICOLON","context":"normal","value":";","line":11,"start":262,"end":263},{"type":"T_CLASS","context":"normal","value":"class","line":13,"start":265,"end":270},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":13,"start":271,"end":282},{"type":"T_EXTENDS","context":"normal","value":"extends","line":13,"start":283,"end":290},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":13,"start":291,"end":296},{"type":"T_PERIOD","context":"normal","value":".","line":13,"start":296,"end":297},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":13,"start":297,"end":306},{"type":"T_LESS_THAN","context":"type","value":"<","line":13,"start":306,"end":307},{"type":"T_IDENTIFIER","context":"type","value":"Props","line":13,"start":307,"end":312},{"type":"T_GREATER_THAN","context":"type","value":">","line":13,"start":312,"end":313},{"type":"T_LCURLY","context":"normal","value":"{","line":13,"start":314,"end":315},{"type":"T_STATIC","context":"normal","value":"static","line":14,"start":318,"end":324},{"type":"T_IDENTIFIER","context":"normal","value":"defaultProps","line":14,"start":325,"end":337},{"type":"T_COLON","context":"type","value":":","line":14,"start":337,"end":338},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":14,"start":339,"end":351},{"type":"T_ASSIGN","context":"normal","value":"=","line":14,"start":352,"end":353},{"type":"T_LCURLY","context":"normal","value":"{","line":14,"start":354,"end":355},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":14,"start":355,"end":358},{"type":"T_COLON","context":"normal","value":":","line":14,"start":358,"end":359},{"type":"T_NUMBER","context":"normal","value":"3","line":14,"start":360,"end":361},{"type":"T_RCURLY","context":"normal","value":"}","line":14,"start":361,"end":362},{"type":"T_SEMICOLON","context":"normal","value":";","line":14,"start":362,"end":363},{"type":"T_RCURLY","context":"normal","value":"}","line":15,"start":364,"end":365},{"type":"Line","context":"comment","value":"// Error, missing annotation for Config.","line":17,"start":367,"end":407},{"type":"T_CONST","context":"normal","value":"const","line":18,"start":408,"end":413},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":18,"start":414,"end":433},{"type":"T_ASSIGN","context":"normal","value":"=","line":18,"start":434,"end":435},{"type":"T_IDENTIFIER","context":"normal","value":"trivialHOC","line":18,"start":436,"end":446},{"type":"T_LPAREN","context":"normal","value":"(","line":18,"start":446,"end":447},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":18,"start":447,"end":458},{"type":"T_RPAREN","context":"normal","value":")","line":18,"start":458,"end":459},{"type":"T_SEMICOLON","context":"normal","value":";","line":18,"start":459,"end":460},{"type":"T_IDENTIFIER","context":"normal","value":"module","line":20,"start":462,"end":468},{"type":"T_PERIOD","context":"normal","value":".","line":20,"start":468,"end":469},{"type":"T_IDENTIFIER","context":"normal","value":"exports","line":20,"start":469,"end":476},{"type":"T_ASSIGN","context":"normal","value":"=","line":20,"start":477,"end":478},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":20,"start":479,"end":498},{"type":"T_SEMICOLON","context":"normal","value":";","line":20,"start":498,"end":499}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. [signature-verification-failure]","context":"const MyEnhancedComponent = trivialHOC(MyComponent);","source":"-","start":{"line":18,"column":29,"offset":436},"end":{"line":18,"column":51,"offset":459}}],"operation":null}]}
If your component has no defaultProps
, you can use Props
as a type argument for Config
.
If your component does have defaultProps
, you don’t want to just add Props
as a type argument to trivialHOC
because that will get rid of the
defaultProps
information that flow has about your component.
This is where React.Config<Props, DefaultProps>
comes in handy! We can use the type for Props and DefaultProps to calculate the
Config
type for our component.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import * as React from 'react';
function trivialHOC<Config: {}>(
Component: React.AbstractComponent<Config>,
): React.AbstractComponent<Config> {
return Component;
}
type DefaultProps = {| foo: number |};
type Props = {...DefaultProps, bar: number};
class MyComponent extends React.Component<Props> {
static defaultProps: DefaultProps = {foo: 3};
}
const MyEnhancedComponent = trivialHOC<React.Config<Props, DefaultProps>>(MyComponent);
module.exports = MyEnhancedComponent;
|
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. [signature-verification-failure]
{"value":"//@flow\nimport * as React from 'react';\n\nfunction trivialHOC<Config: {}>(\n Component: React.AbstractComponent<Config>,\n): React.AbstractComponent<Config> {\n return Component;\n}\n\ntype DefaultProps = {| foo: number |};\ntype Props = {...DefaultProps, bar: number};\n\nclass MyComponent extends React.Component<Props> {\n static defaultProps: DefaultProps = {foo: 3};\n}\n\nconst MyEnhancedComponent = trivialHOC<React.Config<Props, DefaultProps>>(MyComponent);\n\n// Ok!\nmodule.exports = MyEnhancedComponent;\n","tokens":[{"type":"Line","context":"comment","value":"//@flow","line":1,"start":0,"end":7},{"type":"T_IMPORT","context":"normal","value":"import","line":2,"start":8,"end":14},{"type":"T_MULT","context":"normal","value":"*","line":2,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"as","line":2,"start":17,"end":19},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":2,"start":20,"end":25},{"type":"T_IDENTIFIER","context":"normal","value":"from","line":2,"start":26,"end":30},{"type":"T_STRING","context":"normal","value":"'react'","line":2,"start":31,"end":38},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":38,"end":39},{"type":"T_FUNCTION","context":"normal","value":"function","line":4,"start":41,"end":49},{"type":"T_IDENTIFIER","context":"normal","value":"trivialHOC","line":4,"start":50,"end":60},{"type":"T_LESS_THAN","context":"type","value":"<","line":4,"start":60,"end":61},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":4,"start":61,"end":67},{"type":"T_COLON","context":"type","value":":","line":4,"start":67,"end":68},{"type":"T_LCURLY","context":"type","value":"{","line":4,"start":69,"end":70},{"type":"T_RCURLY","context":"type","value":"}","line":4,"start":70,"end":71},{"type":"T_GREATER_THAN","context":"type","value":">","line":4,"start":71,"end":72},{"type":"T_LPAREN","context":"normal","value":"(","line":4,"start":72,"end":73},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":5,"start":76,"end":85},{"type":"T_COLON","context":"type","value":":","line":5,"start":85,"end":86},{"type":"T_IDENTIFIER","context":"type","value":"React","line":5,"start":87,"end":92},{"type":"T_PERIOD","context":"type","value":".","line":5,"start":92,"end":93},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":5,"start":93,"end":110},{"type":"T_LESS_THAN","context":"type","value":"<","line":5,"start":110,"end":111},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":5,"start":111,"end":117},{"type":"T_GREATER_THAN","context":"type","value":">","line":5,"start":117,"end":118},{"type":"T_COMMA","context":"normal","value":",","line":5,"start":118,"end":119},{"type":"T_RPAREN","context":"normal","value":")","line":6,"start":120,"end":121},{"type":"T_COLON","context":"type","value":":","line":6,"start":121,"end":122},{"type":"T_IDENTIFIER","context":"type","value":"React","line":6,"start":123,"end":128},{"type":"T_PERIOD","context":"type","value":".","line":6,"start":128,"end":129},{"type":"T_IDENTIFIER","context":"type","value":"AbstractComponent","line":6,"start":129,"end":146},{"type":"T_LESS_THAN","context":"type","value":"<","line":6,"start":146,"end":147},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":6,"start":147,"end":153},{"type":"T_GREATER_THAN","context":"type","value":">","line":6,"start":153,"end":154},{"type":"T_LCURLY","context":"normal","value":"{","line":6,"start":155,"end":156},{"type":"T_RETURN","context":"normal","value":"return","line":7,"start":159,"end":165},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":7,"start":166,"end":175},{"type":"T_SEMICOLON","context":"normal","value":";","line":7,"start":175,"end":176},{"type":"T_RCURLY","context":"normal","value":"}","line":8,"start":177,"end":178},{"type":"T_TYPE","context":"normal","value":"type","line":10,"start":180,"end":184},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":10,"start":185,"end":197},{"type":"T_ASSIGN","context":"type","value":"=","line":10,"start":198,"end":199},{"type":"T_LCURLYBAR","context":"type","value":"{|","line":10,"start":200,"end":202},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":10,"start":203,"end":206},{"type":"T_COLON","context":"type","value":":","line":10,"start":206,"end":207},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":10,"start":208,"end":214},{"type":"T_RCURLYBAR","context":"type","value":"|}","line":10,"start":215,"end":217},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":217,"end":218},{"type":"T_TYPE","context":"normal","value":"type","line":11,"start":219,"end":223},{"type":"T_IDENTIFIER","context":"type","value":"Props","line":11,"start":224,"end":229},{"type":"T_ASSIGN","context":"type","value":"=","line":11,"start":230,"end":231},{"type":"T_LCURLY","context":"type","value":"{","line":11,"start":232,"end":233},{"type":"T_ELLIPSIS","context":"type","value":"...","line":11,"start":233,"end":236},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":11,"start":236,"end":248},{"type":"T_COMMA","context":"type","value":",","line":11,"start":248,"end":249},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":11,"start":250,"end":253},{"type":"T_COLON","context":"type","value":":","line":11,"start":253,"end":254},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":11,"start":255,"end":261},{"type":"T_RCURLY","context":"type","value":"}","line":11,"start":261,"end":262},{"type":"T_SEMICOLON","context":"normal","value":";","line":11,"start":262,"end":263},{"type":"T_CLASS","context":"normal","value":"class","line":13,"start":265,"end":270},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":13,"start":271,"end":282},{"type":"T_EXTENDS","context":"normal","value":"extends","line":13,"start":283,"end":290},{"type":"T_IDENTIFIER","context":"normal","value":"React","line":13,"start":291,"end":296},{"type":"T_PERIOD","context":"normal","value":".","line":13,"start":296,"end":297},{"type":"T_IDENTIFIER","context":"normal","value":"Component","line":13,"start":297,"end":306},{"type":"T_LESS_THAN","context":"type","value":"<","line":13,"start":306,"end":307},{"type":"T_IDENTIFIER","context":"type","value":"Props","line":13,"start":307,"end":312},{"type":"T_GREATER_THAN","context":"type","value":">","line":13,"start":312,"end":313},{"type":"T_LCURLY","context":"normal","value":"{","line":13,"start":314,"end":315},{"type":"T_STATIC","context":"normal","value":"static","line":14,"start":318,"end":324},{"type":"T_IDENTIFIER","context":"normal","value":"defaultProps","line":14,"start":325,"end":337},{"type":"T_COLON","context":"type","value":":","line":14,"start":337,"end":338},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":14,"start":339,"end":351},{"type":"T_ASSIGN","context":"normal","value":"=","line":14,"start":352,"end":353},{"type":"T_LCURLY","context":"normal","value":"{","line":14,"start":354,"end":355},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":14,"start":355,"end":358},{"type":"T_COLON","context":"normal","value":":","line":14,"start":358,"end":359},{"type":"T_NUMBER","context":"normal","value":"3","line":14,"start":360,"end":361},{"type":"T_RCURLY","context":"normal","value":"}","line":14,"start":361,"end":362},{"type":"T_SEMICOLON","context":"normal","value":";","line":14,"start":362,"end":363},{"type":"T_RCURLY","context":"normal","value":"}","line":15,"start":364,"end":365},{"type":"T_CONST","context":"normal","value":"const","line":17,"start":367,"end":372},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":17,"start":373,"end":392},{"type":"T_ASSIGN","context":"normal","value":"=","line":17,"start":393,"end":394},{"type":"T_IDENTIFIER","context":"normal","value":"trivialHOC","line":17,"start":395,"end":405},{"type":"T_LESS_THAN","context":"type","value":"<","line":17,"start":405,"end":406},{"type":"T_IDENTIFIER","context":"type","value":"React","line":17,"start":406,"end":411},{"type":"T_PERIOD","context":"type","value":".","line":17,"start":411,"end":412},{"type":"T_IDENTIFIER","context":"type","value":"Config","line":17,"start":412,"end":418},{"type":"T_LESS_THAN","context":"type","value":"<","line":17,"start":418,"end":419},{"type":"T_IDENTIFIER","context":"type","value":"Props","line":17,"start":419,"end":424},{"type":"T_COMMA","context":"type","value":",","line":17,"start":424,"end":425},{"type":"T_IDENTIFIER","context":"type","value":"DefaultProps","line":17,"start":426,"end":438},{"type":"T_GREATER_THAN","context":"type","value":">","line":17,"start":438,"end":439},{"type":"T_GREATER_THAN","context":"type","value":">","line":17,"start":439,"end":440},{"type":"T_LPAREN","context":"normal","value":"(","line":17,"start":440,"end":441},{"type":"T_IDENTIFIER","context":"normal","value":"MyComponent","line":17,"start":441,"end":452},{"type":"T_RPAREN","context":"normal","value":")","line":17,"start":452,"end":453},{"type":"T_SEMICOLON","context":"normal","value":";","line":17,"start":453,"end":454},{"type":"Line","context":"comment","value":"// Ok!","line":19,"start":456,"end":462},{"type":"T_IDENTIFIER","context":"normal","value":"module","line":20,"start":463,"end":469},{"type":"T_PERIOD","context":"normal","value":".","line":20,"start":469,"end":470},{"type":"T_IDENTIFIER","context":"normal","value":"exports","line":20,"start":470,"end":477},{"type":"T_ASSIGN","context":"normal","value":"=","line":20,"start":478,"end":479},{"type":"T_IDENTIFIER","context":"normal","value":"MyEnhancedComponent","line":20,"start":480,"end":499},{"type":"T_SEMICOLON","context":"normal","value":";","line":20,"start":499,"end":500}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. [signature-verification-failure]","context":"const MyEnhancedComponent = trivialHOC<React.Config<Props, DefaultProps>>(MyComponent);","source":"-","start":{"line":17,"column":29,"offset":395},"end":{"line":17,"column":86,"offset":453}}],"operation":null}]}