From 9b45d2bdc82279c41ae8b23ba0f8a9f3b255424b Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 29 Nov 2018 07:39:55 -0800 Subject: [PATCH] Fixed React.lazy definition and tests --- lib/react.js | 2 +- tests/react_16_6/lazy.js | 13 +- tests/react_16_6/react_16_6.exp | 122 ++++++++++++++---- tests/type-at-pos_react/type-at-pos_react.exp | 2 +- 4 files changed, 113 insertions(+), 26 deletions(-) diff --git a/lib/react.js b/lib/react.js index ee99eb43b65..95934ff5f56 100644 --- a/lib/react.js +++ b/lib/react.js @@ -291,7 +291,7 @@ declare module react { ): React$StatelessFunctionalComponent

; declare export function lazy

( - component: () => React$ComponentType

, + component: () => Promise<{ default: React$ComponentType

}>, ): React$ComponentType

; declare type MaybeCleanUpFn = ?(() => mixed); diff --git a/tests/react_16_6/lazy.js b/tests/react_16_6/lazy.js index b0286bae9ee..decea1d3ee1 100644 --- a/tests/react_16_6/lazy.js +++ b/tests/react_16_6/lazy.js @@ -6,14 +6,23 @@ type Props = {| foo: number |}; function FunctionComponent(x: Props): React.Node { return null } class ClassComponent extends React.Component {} -const LazyFunctionComponent = React.lazy( () => FunctionComponent ); +React.lazy(() => FunctionComponent); // Error incompatible with Promise +React.lazy(() => ClassComponent); // Error incompatible with Promise +React.lazy(() => Promise.resolve(FunctionComponent)); // Error property default is missing +React.lazy(() => Promise.resolve(ClassComponent)); // Error property default is missing + +const LazyFunctionComponent = React.lazy( + () => Promise.resolve({default: FunctionComponent}) +); const _a = ; const _b = ; // Error missing foo const _c = ; // Error extra bar const _d = ; // Error wrong type for foo -const LazyClassComponent = React.lazy( () => ClassComponent ); +const LazyClassComponent = React.lazy( + () => Promise.resolve({default: ClassComponent}) +); const _e = ; const _f = ; // Error missing foo diff --git a/tests/react_16_6/react_16_6.exp b/tests/react_16_6/react_16_6.exp index 3de84b4147c..2d938783074 100644 --- a/tests/react_16_6/react_16_6.exp +++ b/tests/react_16_6/react_16_6.exp @@ -41,12 +41,90 @@ References: ^^^^^^^^^^^^^^^^^^^^^ [4] +Error ----------------------------------------------------------------------------------------------------- lazy.js:9:12 + +Cannot call `React.lazy` with function bound to `component` because function [1] is incompatible with `Promise` [2] in +the return value. + + lazy.js:9:12 + 9| React.lazy(() => FunctionComponent); // Error incompatible with Promise + ^^^^^^^^^^^^^^^^^^^^^^^ + +References: + lazy.js:6:1 + 6| function FunctionComponent(x: Props): React.Node { return null } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + /react.js:294:22 + 294| component: () => Promise<{ default: React$ComponentType

}>, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ---------------------------------------------------------------------------------------------------- lazy.js:10:12 + +Cannot call `React.lazy` with function bound to `component` because class `ClassComponent` [1] is incompatible with +`Promise` [2] in the return value. + + lazy.js:10:12 + 10| React.lazy(() => ClassComponent); // Error incompatible with Promise + ^^^^^^^^^^^^^^^^^^^^ + +References: + lazy.js:7:7 + 7| class ClassComponent extends React.Component {} + ^^^^^^^^^^^^^^ [1] + /react.js:294:22 + 294| component: () => Promise<{ default: React$ComponentType

}>, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + + +Error ---------------------------------------------------------------------------------------------------- lazy.js:11:12 + +Cannot call `React.lazy` with function bound to `component` because property `default` is missing in function [1] but +exists in object type [2] in type argument `R` [3] of the return value. + + lazy.js:11:12 + 11| React.lazy(() => Promise.resolve(FunctionComponent)); // Error property default is missing + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + lazy.js:6:1 + 6| function FunctionComponent(x: Props): React.Node { return null } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + /react.js:294:30 + 294| component: () => Promise<{ default: React$ComponentType

}>, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + /core.js:612:24 + 612| declare class Promise<+R> { + ^ [3] + + Error ---------------------------------------------------------------------------------------------------- lazy.js:12:12 -Cannot create `LazyFunctionComponent` element because property `foo` is missing in props [1] but exists in `Props` [2]. +Cannot call `React.lazy` with function bound to `component` because property `default` is missing in statics of +`ClassComponent` [1] but exists in object type [2] in type argument `R` [3] of the return value. lazy.js:12:12 - 12| const _b = ; // Error missing foo + 12| React.lazy(() => Promise.resolve(ClassComponent)); // Error property default is missing + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + lazy.js:7:7 + 7| class ClassComponent extends React.Component {} + ^^^^^^^^^^^^^^ [1] + /react.js:294:30 + 294| component: () => Promise<{ default: React$ComponentType

}>, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + /core.js:612:24 + 612| declare class Promise<+R> { + ^ [3] + + +Error ---------------------------------------------------------------------------------------------------- lazy.js:19:12 + +Cannot create `LazyFunctionComponent` element because property `foo` is missing in props [1] but exists in `Props` [2]. + + lazy.js:19:12 + 19| const _b = ; // Error missing foo ^^^^^^^^^^^^^^^^^^^^^^^^^ [1] References: @@ -55,12 +133,12 @@ References: ^^^^^ [2] -Error ---------------------------------------------------------------------------------------------------- lazy.js:13:12 +Error ---------------------------------------------------------------------------------------------------- lazy.js:20:12 Cannot create `LazyFunctionComponent` element because property `bar` is missing in `Props` [1] but exists in props [2]. - lazy.js:13:12 - 13| const _c = ; // Error extra bar + lazy.js:20:12 + 20| const _c = ; // Error extra bar ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] References: @@ -69,29 +147,29 @@ References: ^^^^^ [1] -Error ---------------------------------------------------------------------------------------------------- lazy.js:14:12 +Error ---------------------------------------------------------------------------------------------------- lazy.js:21:12 Cannot create `LazyFunctionComponent` element because string [1] is incompatible with number [2] in property `foo`. - lazy.js:14:12 - 14| const _d = ; // Error wrong type for foo + lazy.js:21:12 + 21| const _d = ; // Error wrong type for foo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ References: - lazy.js:14:39 - 14| const _d = ; // Error wrong type for foo + lazy.js:21:39 + 21| const _d = ; // Error wrong type for foo ^^^^^^^^ [1] lazy.js:5:22 5| type Props = {| foo: number |}; ^^^^^^ [2] -Error ---------------------------------------------------------------------------------------------------- lazy.js:19:12 +Error ---------------------------------------------------------------------------------------------------- lazy.js:28:12 Cannot create `LazyClassComponent` element because property `foo` is missing in props [1] but exists in `Props` [2]. - lazy.js:19:12 - 19| const _f = ; // Error missing foo + lazy.js:28:12 + 28| const _f = ; // Error missing foo ^^^^^^^^^^^^^^^^^^^^^^ [1] References: @@ -100,12 +178,12 @@ References: ^^^^^ [2] -Error ---------------------------------------------------------------------------------------------------- lazy.js:20:12 +Error ---------------------------------------------------------------------------------------------------- lazy.js:29:12 Cannot create `LazyClassComponent` element because property `bar` is missing in `Props` [1] but exists in props [2]. - lazy.js:20:12 - 20| const _g = ; // Error extra bar + lazy.js:29:12 + 29| const _g = ; // Error extra bar ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] References: @@ -114,17 +192,17 @@ References: ^^^^^ [1] -Error ---------------------------------------------------------------------------------------------------- lazy.js:21:12 +Error ---------------------------------------------------------------------------------------------------- lazy.js:30:12 Cannot create `LazyClassComponent` element because string [1] is incompatible with number [2] in property `foo`. - lazy.js:21:12 - 21| const _h = ; // Error wrong type for foo + lazy.js:30:12 + 30| const _h = ; // Error wrong type for foo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ References: - lazy.js:21:36 - 21| const _h = ; // Error wrong type for foo + lazy.js:30:36 + 30| const _h = ; // Error wrong type for foo ^^^^^^^^ [1] lazy.js:5:22 5| type Props = {| foo: number |}; @@ -222,7 +300,7 @@ References: -Found 14 errors +Found 18 errors Only showing the most relevant union/intersection branches. To see all branches, re-run Flow with --show-all-branches diff --git a/tests/type-at-pos_react/type-at-pos_react.exp b/tests/type-at-pos_react/type-at-pos_react.exp index d64796c3370..7e58c972231 100644 --- a/tests/type-at-pos_react/type-at-pos_react.exp +++ b/tests/type-at-pos_react/type-at-pos_react.exp @@ -1,5 +1,5 @@ react_component.js:3:9 = { - "type":"{|+Children: {+count: (children: ChildrenArray) => number, +forEach: (children: ChildrenArray, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: (children: ChildrenArray, fn: (child: $NonMaybeType, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType>, +only: (children: ChildrenArray) => $NonMaybeType, +toArray: (children: ChildrenArray) => Array<$NonMaybeType>}, +ChildrenArray: type ChildrenArray<+T> = $ReadOnlyArray> | T, +Component: class React$Component, +ComponentType: type ComponentType

= React$ComponentType

, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +Context: type Context = React$Context, +DOM: any, +Element: type Element<+C> = React$Element, +ElementConfig: type ElementConfig = React$ElementConfig, +ElementProps: type ElementProps = React$ElementProps, +ElementRef: type ElementRef = React$ElementRef, +ElementType: type ElementType = React$ElementType, +Fragment: ({children: ?React$Node}) => React$Node, +Key: type Key = React$Key, +Node: type Node = React$Node, +Portal: type Portal = React$Portal, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent, +Ref: type Ref = React$Ref, +StatelessFunctionalComponent: type StatelessFunctionalComponent

= React$StatelessFunctionalComponent

, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: (propTypes: $Subtype<{[_: $Keys]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: (defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context, +createElement: React$CreateElement, +createFactory: (type: ElementType) => React$ElementFactory, +createRef: () => {current: (null | T)}, +default: {|+Children: {+count: (children: ChildrenArray) => number, +forEach: (children: ChildrenArray, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: (children: ChildrenArray, fn: (child: $NonMaybeType, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType>, +only: (children: ChildrenArray) => $NonMaybeType, +toArray: (children: ChildrenArray) => Array<$NonMaybeType>}, +Component: class React$Component, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +DOM: any, +Fragment: ({children: ?React$Node}) => React$Node, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: (propTypes: $Subtype<{[_: $Keys]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: (defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context, +createElement: React$CreateElement, +createFactory: (type: ElementType) => React$ElementFactory, +createRef: () => {current: (null | T)}, +isValidElement: (element: any) => boolean, +lazy:

(component: () => React$ComponentType

) => React$ComponentType

, +memo:

(component: React$StatelessFunctionalComponent

, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent

, +useCallback: ) => mixed>(callback: T, inputs: ?$ReadOnlyArray) => T, +useContext: (context: React$Context, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useImperativeMethods: (ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useMemo: (create: () => T, inputs: ?$ReadOnlyArray) => T, +useReducer: (reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: (initialValue: ?T) => {current: (T | null)}, +useState: (initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}, +isValidElement: (element: any) => boolean, +lazy:

(component: () => React$ComponentType

) => React$ComponentType

, +memo:

(component: React$StatelessFunctionalComponent

, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent

, +useCallback: ) => mixed>(callback: T, inputs: ?$ReadOnlyArray) => T, +useContext: (context: React$Context, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useImperativeMethods: (ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useMemo: (create: () => T, inputs: ?$ReadOnlyArray) => T, +useReducer: (reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: (initialValue: ?T) => {current: (T | null)}, +useState: (initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}", + "type":"{|+Children: {+count: (children: ChildrenArray) => number, +forEach: (children: ChildrenArray, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: (children: ChildrenArray, fn: (child: $NonMaybeType, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType>, +only: (children: ChildrenArray) => $NonMaybeType, +toArray: (children: ChildrenArray) => Array<$NonMaybeType>}, +ChildrenArray: type ChildrenArray<+T> = $ReadOnlyArray> | T, +Component: class React$Component, +ComponentType: type ComponentType

= React$ComponentType

, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +Context: type Context = React$Context, +DOM: any, +Element: type Element<+C> = React$Element, +ElementConfig: type ElementConfig = React$ElementConfig, +ElementProps: type ElementProps = React$ElementProps, +ElementRef: type ElementRef = React$ElementRef, +ElementType: type ElementType = React$ElementType, +Fragment: ({children: ?React$Node}) => React$Node, +Key: type Key = React$Key, +Node: type Node = React$Node, +Portal: type Portal = React$Portal, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent, +Ref: type Ref = React$Ref, +StatelessFunctionalComponent: type StatelessFunctionalComponent

= React$StatelessFunctionalComponent

, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: (propTypes: $Subtype<{[_: $Keys]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: (defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context, +createElement: React$CreateElement, +createFactory: (type: ElementType) => React$ElementFactory, +createRef: () => {current: (null | T)}, +default: {|+Children: {+count: (children: ChildrenArray) => number, +forEach: (children: ChildrenArray, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: (children: ChildrenArray, fn: (child: $NonMaybeType, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType>, +only: (children: ChildrenArray) => $NonMaybeType, +toArray: (children: ChildrenArray) => Array<$NonMaybeType>}, +Component: class React$Component, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +DOM: any, +Fragment: ({children: ?React$Node}) => React$Node, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: (propTypes: $Subtype<{[_: $Keys]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: (defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context, +createElement: React$CreateElement, +createFactory: (type: ElementType) => React$ElementFactory, +createRef: () => {current: (null | T)}, +isValidElement: (element: any) => boolean, +lazy:

(component: () => Promise<{default: React$ComponentType

}>) => React$ComponentType

, +memo:

(component: React$StatelessFunctionalComponent

, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent

, +useCallback: ) => mixed>(callback: T, inputs: ?$ReadOnlyArray) => T, +useContext: (context: React$Context, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useImperativeMethods: (ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useMemo: (create: () => T, inputs: ?$ReadOnlyArray) => T, +useReducer: (reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: (initialValue: ?T) => {current: (T | null)}, +useState: (initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}, +isValidElement: (element: any) => boolean, +lazy:

(component: () => Promise<{default: React$ComponentType

}>) => React$ComponentType

, +memo:

(component: React$StatelessFunctionalComponent

, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent

, +useCallback: ) => mixed>(callback: T, inputs: ?$ReadOnlyArray) => T, +useContext: (context: React$Context, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useImperativeMethods: (ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray) => void, +useMemo: (create: () => T, inputs: ?$ReadOnlyArray) => T, +useReducer: (reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: (initialValue: ?T) => {current: (T | null)}, +useState: (initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}", "reasons":[], "loc":{ "source":"react_component.js",