Skip to content

Commit dabf49e

Browse files
author
Brian Vaughn
committed
Make React.Suspense "fallback" prop optional (and add nested Suspense test cases)
1 parent 2fdcda5 commit dabf49e

File tree

4 files changed

+27
-38
lines changed

4 files changed

+27
-38
lines changed

lib/react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ declare module react {
260260

261261
declare export var Suspense: React$ComponentType<{
262262
children?: ?React$Node,
263-
fallback: React$Node,
263+
fallback?: React$Node,
264264
maxDuration?: number
265265
}>; // 16.6+
266266

tests/react_16_6/Suspense.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ function Loading() {
88
return <div>Loading...</div>;
99
}
1010

11-
{
12-
<Suspense /> // Error: fallback is missing in props
13-
}
14-
1511
{
1612
<Suspense fallback={<Loading />} maxDuration="abc" /> // Error: string is incompatible with number
1713
}
@@ -24,18 +20,30 @@ function Loading() {
2420
<Suspense fallback={<Loading/>} />
2521
}
2622

23+
{
24+
<Suspense fallback={<Loading/>} maxDuration={1000} />
25+
}
26+
27+
{
28+
<Suspense fallback={<Loading/>} maxDuration={1000}>
29+
<div>Hello</div>
30+
</Suspense>
31+
}
32+
2733
{
2834
<Suspense fallback={<Loading/>}>
29-
<Loading />
35+
<Suspense />
3036
</Suspense>
3137
}
3238

3339
{
34-
<Suspense fallback={<Loading/>} maxDuration={1000} />
40+
<Suspense fallback={<Loading/>}>
41+
<Suspense fallback={undefined} />
42+
</Suspense>
3543
}
3644

3745
{
38-
<Suspense fallback={<Loading/>} maxDuration={1000}>
39-
<Loading />
46+
<Suspense fallback={<Loading/>}>
47+
<Suspense fallback={null} />
4048
</Suspense>
41-
}
49+
}

tests/react_16_6/react_16_6.exp

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,29 @@
11
Error ------------------------------------------------------------------------------------------------- Suspense.js:12:3
22

3-
Cannot create `Suspense` element because property `fallback` is missing in props [1] but exists in object type [2].
4-
5-
Suspense.js:12:3
6-
12| <Suspense /> // Error: fallback is missing in props
7-
^^^^^^^^^^^^ [1]
8-
9-
References:
10-
<BUILTINS>/react.js:253:52
11-
v
12-
253| declare export var Suspense: React$ComponentType<{
13-
254| children?: ?React$Node,
14-
255| fallback: React$Node,
15-
256| maxDuration?: number
16-
257| }>; // 16.6+
17-
^ [2]
18-
19-
20-
Error ------------------------------------------------------------------------------------------------- Suspense.js:16:3
21-
223
Cannot create `Suspense` element because string [1] is incompatible with number [2] in property `maxDuration`.
234

24-
Suspense.js:16:3
25-
16| <Suspense fallback={<Loading />} maxDuration="abc" /> // Error: string is incompatible with number
5+
Suspense.js:12:3
6+
12| <Suspense fallback={<Loading />} maxDuration="abc" /> // Error: string is incompatible with number
267
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278

289
References:
29-
Suspense.js:16:48
30-
16| <Suspense fallback={<Loading />} maxDuration="abc" /> // Error: string is incompatible with number
10+
Suspense.js:12:48
11+
12| <Suspense fallback={<Loading />} maxDuration="abc" /> // Error: string is incompatible with number
3112
^^^^^ [1]
3213
<BUILTINS>/react.js:256:19
3314
256| maxDuration?: number
3415
^^^^^^ [2]
3516

3617

37-
Error ------------------------------------------------------------------------------------------------- Suspense.js:20:3
18+
Error ------------------------------------------------------------------------------------------------- Suspense.js:16:3
3819

3920
Cannot create `Suspense` element because in property `fallback`:
4021
- Either inexact function [1] is incompatible with exact `React.Element` [2].
4122
- Or function [1] is incompatible with `React.Portal` [3].
4223
- Or property `@@iterator` is missing in function [1] but exists in `$Iterable` [4].
4324

44-
Suspense.js:20:3
45-
20| <Suspense fallback={Loading} /> // Error: function is incompatible with exact React.Element
25+
Suspense.js:16:3
26+
16| <Suspense fallback={Loading} /> // Error: function is incompatible with exact React.Element
4627
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4728

4829
References:
@@ -241,7 +222,7 @@ References:
241222

242223

243224

244-
Found 15 errors
225+
Found 14 errors
245226

246227
Only showing the most relevant union/intersection branches.
247228
To see all branches, re-run Flow with --show-all-branches

tests/type-at-pos_react/type-at-pos_react.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
react_component.js:3:9 = {
2-
"type":"{|+Children: {+count: (children: ChildrenArray<any>) => number, +forEach: <T>(children: ChildrenArray<T>, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: <T, U>(children: ChildrenArray<T>, fn: (child: $NonMaybeType<T>, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType<U>>, +only: <T>(children: ChildrenArray<T>) => $NonMaybeType<T>, +toArray: <T>(children: ChildrenArray<T>) => Array<$NonMaybeType<T>>}, +ChildrenArray: type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T, +Component: class React$Component<Props, State = void>, +ComponentType: type ComponentType<P> = React$ComponentType<P>, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +Context: type Context<T> = React$Context<T>, +DOM: any, +Element: type Element<+C> = React$Element<C>, +ElementConfig: type ElementConfig<C> = React$ElementConfig<C>, +ElementProps: type ElementProps<C> = React$ElementProps<C>, +ElementRef: type ElementRef<C> = React$ElementRef<C>, +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<Props, State = void>, +Ref: type Ref<C> = React$Ref<C>, +StatelessFunctionalComponent: type StatelessFunctionalComponent<P> = React$StatelessFunctionalComponent<P>, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback: React$Node, maxDuration?: number}>, +checkPropTypes: <V>(propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: <T>(defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context<T>, +createElement: React$CreateElement, +createFactory: <ElementType: React$ElementType>(type: ElementType) => React$ElementFactory<ElementType>, +createRef: <T>() => {current: (null | T)}, +default: {|+Children: {+count: (children: ChildrenArray<any>) => number, +forEach: <T>(children: ChildrenArray<T>, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: <T, U>(children: ChildrenArray<T>, fn: (child: $NonMaybeType<T>, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType<U>>, +only: <T>(children: ChildrenArray<T>) => $NonMaybeType<T>, +toArray: <T>(children: ChildrenArray<T>) => Array<$NonMaybeType<T>>}, +Component: class React$Component<Props, State = void>, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +DOM: any, +Fragment: ({children: ?React$Node}) => React$Node, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent<Props, State = void>, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback: React$Node, maxDuration?: number}>, +checkPropTypes: <V>(propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: <T>(defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context<T>, +createElement: React$CreateElement, +createFactory: <ElementType: React$ElementType>(type: ElementType) => React$ElementFactory<ElementType>, +createRef: <T>() => {current: (null | T)}, +isValidElement: (element: any) => boolean, +lazy: <P>(component: () => React$ComponentType<P>) => React$ComponentType<P>, +memo: <P>(component: React$StatelessFunctionalComponent<P>, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent<P>, +useCallback: <T>(callback: () => (T | void), inputs: ?$ReadOnlyArray<mixed>) => T, +useContext: <T>(context: React$Context<T>, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useImperativeMethods: <T>(ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray<mixed>) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useMemo: <T>(create: () => T, inputs: ?$ReadOnlyArray<mixed>) => T, +useReducer: <S, A>(reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: <T>(initialValue: ?T) => {current: (T | null)}, +useState: <S>(initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}, +isValidElement: (element: any) => boolean, +lazy: <P>(component: () => React$ComponentType<P>) => React$ComponentType<P>, +memo: <P>(component: React$StatelessFunctionalComponent<P>, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent<P>, +useCallback: <T>(callback: () => (T | void), inputs: ?$ReadOnlyArray<mixed>) => T, +useContext: <T>(context: React$Context<T>, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useImperativeMethods: <T>(ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray<mixed>) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useMemo: <T>(create: () => T, inputs: ?$ReadOnlyArray<mixed>) => T, +useReducer: <S, A>(reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: <T>(initialValue: ?T) => {current: (T | null)}, +useState: <S>(initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}",
2+
"type":"{|+Children: {+count: (children: ChildrenArray<any>) => number, +forEach: <T>(children: ChildrenArray<T>, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: <T, U>(children: ChildrenArray<T>, fn: (child: $NonMaybeType<T>, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType<U>>, +only: <T>(children: ChildrenArray<T>) => $NonMaybeType<T>, +toArray: <T>(children: ChildrenArray<T>) => Array<$NonMaybeType<T>>}, +ChildrenArray: type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T, +Component: class React$Component<Props, State = void>, +ComponentType: type ComponentType<P> = React$ComponentType<P>, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +Context: type Context<T> = React$Context<T>, +DOM: any, +Element: type Element<+C> = React$Element<C>, +ElementConfig: type ElementConfig<C> = React$ElementConfig<C>, +ElementProps: type ElementProps<C> = React$ElementProps<C>, +ElementRef: type ElementRef<C> = React$ElementRef<C>, +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<Props, State = void>, +Ref: type Ref<C> = React$Ref<C>, +StatelessFunctionalComponent: type StatelessFunctionalComponent<P> = React$StatelessFunctionalComponent<P>, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: <V>(propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: <T>(defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context<T>, +createElement: React$CreateElement, +createFactory: <ElementType: React$ElementType>(type: ElementType) => React$ElementFactory<ElementType>, +createRef: <T>() => {current: (null | T)}, +default: {|+Children: {+count: (children: ChildrenArray<any>) => number, +forEach: <T>(children: ChildrenArray<T>, fn: (child: T, index: number) => mixed, thisArg?: mixed) => void, +map: <T, U>(children: ChildrenArray<T>, fn: (child: $NonMaybeType<T>, index: number) => U, thisArg?: mixed) => Array<$NonMaybeType<U>>, +only: <T>(children: ChildrenArray<T>) => $NonMaybeType<T>, +toArray: <T>(children: ChildrenArray<T>) => Array<$NonMaybeType<T>>}, +Component: class React$Component<Props, State = void>, +ConcurrentMode: ({children: ?React$Node}) => React$Node, +DOM: any, +Fragment: ({children: ?React$Node}) => React$Node, +PropTypes: ReactPropTypes, +PureComponent: class React$PureComponent<Props, State = void>, +StrictMode: ({children: ?React$Node}) => React$Node, +Suspense: React$ComponentType<{children?: ?React$Node, fallback?: React$Node, maxDuration?: number}>, +checkPropTypes: <V>(propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>, values: V, location: string, componentName: string, getStack: ?(() => ?string)) => void, +cloneElement: React$CloneElement, +createClass: React$CreateClass, +createContext: <T>(defaultValue: T, calculateChangedBits: ?((a: T, b: T) => number)) => React$Context<T>, +createElement: React$CreateElement, +createFactory: <ElementType: React$ElementType>(type: ElementType) => React$ElementFactory<ElementType>, +createRef: <T>() => {current: (null | T)}, +isValidElement: (element: any) => boolean, +lazy: <P>(component: () => React$ComponentType<P>) => React$ComponentType<P>, +memo: <P>(component: React$StatelessFunctionalComponent<P>, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent<P>, +useCallback: <T>(callback: () => (T | void), inputs: ?$ReadOnlyArray<mixed>) => T, +useContext: <T>(context: React$Context<T>, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useImperativeMethods: <T>(ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray<mixed>) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useMemo: <T>(create: () => T, inputs: ?$ReadOnlyArray<mixed>) => T, +useReducer: <S, A>(reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: <T>(initialValue: ?T) => {current: (T | null)}, +useState: <S>(initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}, +isValidElement: (element: any) => boolean, +lazy: <P>(component: () => React$ComponentType<P>) => React$ComponentType<P>, +memo: <P>(component: React$StatelessFunctionalComponent<P>, equal?: (P, P) => boolean) => React$StatelessFunctionalComponent<P>, +useCallback: <T>(callback: () => (T | void), inputs: ?$ReadOnlyArray<mixed>) => T, +useContext: <T>(context: React$Context<T>, observedBits: (void | number | boolean)) => T, +useEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useImperativeMethods: <T>(ref: ?({current: (T | null)} | ((inst: (T | null)) => mixed)), create: () => T, inputs: ?$ReadOnlyArray<mixed>) => void, +useLayoutEffect: (create: () => MaybeCleanUpFn, inputs: ?$ReadOnlyArray<mixed>) => void, +useMemo: <T>(create: () => T, inputs: ?$ReadOnlyArray<mixed>) => T, +useReducer: <S, A>(reducer: (S, A) => S, initialState: S, initialAction: ?A) => [S, (A) => void], +useRef: <T>(initialValue: ?T) => {current: (T | null)}, +useState: <S>(initialState: ((() => S) | S)) => [S, ((((S) => S) | S)) => void], +version: string|}",
33
"reasons":[],
44
"loc":{
55
"source":"react_component.js",

0 commit comments

Comments
 (0)