Skip to content

Commit fe533a4

Browse files
thymikeefacebook-github-bot
authored andcommitted
Flow strict ScrollView; get rid of InternalScrollViewType (#22301)
Summary: Relates to #22100. I left 2 `$FlowFixMe`s as I was not sure how to handle generic `React.Element<>` and which native props can I pass to ScrollView (would be cool to document it once we got proper types there). I also got rid of `InternalScrollViewType` because we have better typings in original `ScrollView` now. Pull Request resolved: #22301 Reviewed By: TheSavior Differential Revision: D13103990 Pulled By: RSNara fbshipit-source-id: 9664ee9d7f570b00992215e10901e5317f24fe5c
1 parent 205171c commit fe533a4

File tree

4 files changed

+49
-90
lines changed

4 files changed

+49
-90
lines changed

Libraries/Components/ScrollView/InternalScrollViewType.js

-46
This file was deleted.

Libraries/Components/ScrollView/ScrollView.js

+46-43
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*
77
* @format
8-
* @flow
8+
* @flow strict-local
99
*/
1010

1111
'use strict';
@@ -18,7 +18,6 @@ const ScrollResponder = require('ScrollResponder');
1818
const ScrollViewStickyHeader = require('ScrollViewStickyHeader');
1919
const StyleSheet = require('StyleSheet');
2020
const View = require('View');
21-
const InternalScrollViewType = require('InternalScrollViewType');
2221

2322
const dismissKeyboard = require('dismissKeyboard');
2423
const flattenStyle = require('flattenStyle');
@@ -27,7 +26,7 @@ const processDecelerationRate = require('processDecelerationRate');
2726
const requireNativeComponent = require('requireNativeComponent');
2827
const resolveAssetSource = require('resolveAssetSource');
2928

30-
import type {PressEvent} from 'CoreEventTypes';
29+
import type {PressEvent, ScrollEvent, LayoutEvent} from 'CoreEventTypes';
3130
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
3231
import type {NativeMethodsMixinType} from 'ReactNativeTypes';
3332
import type {ViewStyleProp} from 'StyleSheet';
@@ -227,7 +226,7 @@ type IOSProps = $ReadOnly<{|
227226
* Fires when the scroll view scrolls to top after the status bar has been tapped
228227
* @platform ios
229228
*/
230-
onScrollToTop?: ?Function,
229+
onScrollToTop?: (event: ScrollEvent) => void,
231230
/**
232231
* When true, shows a horizontal scroll indicator.
233232
* The default value is true.
@@ -410,33 +409,30 @@ export type Props = $ReadOnly<{|
410409
* - `false`, deprecated, use 'never' instead
411410
* - `true`, deprecated, use 'always' instead
412411
*/
413-
/* $FlowFixMe(>=0.92.0 site=react_native_fb) This comment suppresses an error
414-
* found when Flow v0.92 was deployed. To see the error, delete this comment
415-
* and run Flow. */
416412
keyboardShouldPersistTaps?: ?('always' | 'never' | 'handled' | false | true),
417413
/**
418414
* Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop).
419415
*/
420-
onMomentumScrollBegin?: ?Function,
416+
onMomentumScrollBegin?: (event: ScrollEvent) => void,
421417
/**
422418
* Called when the momentum scroll ends (scroll which occurs as the ScrollView glides to a stop).
423419
*/
424-
onMomentumScrollEnd?: ?Function,
420+
onMomentumScrollEnd?: (event: ScrollEvent) => void,
425421

426422
/**
427423
* Fires at most once per frame during scrolling. The frequency of the
428424
* events can be controlled using the `scrollEventThrottle` prop.
429425
*/
430-
onScroll?: ?Function,
426+
onScroll?: (event: ScrollEvent) => void,
431427
/**
432428
* Called when the user begins to drag the scroll view.
433429
*/
434-
onScrollBeginDrag?: ?Function,
430+
onScrollBeginDrag?: (event: ScrollEvent) => void,
435431
/**
436432
* Called when the user stops dragging the scroll view and it either stops
437433
* or begins to glide.
438434
*/
439-
onScrollEndDrag?: ?Function,
435+
onScrollEndDrag?: (event: ScrollEvent) => void,
440436
/**
441437
* Called when scrollable content view of the ScrollView changes.
442438
*
@@ -446,7 +442,7 @@ export type Props = $ReadOnly<{|
446442
* It's implemented using onLayout handler attached to the content container
447443
* which this ScrollView renders.
448444
*/
449-
onContentSizeChange?: ?Function,
445+
onContentSizeChange?: (contentWidth: number, contentHeight: number) => void,
450446
onKeyboardDidShow?: (event: PressEvent) => void,
451447
/**
452448
* When true, the scroll view stops on multiples of the scroll view's size
@@ -525,6 +521,7 @@ export type Props = $ReadOnly<{|
525521
*
526522
* See [RefreshControl](docs/refreshcontrol.html).
527523
*/
524+
// $FlowFixMe - how to handle generic type without existential opereator?
528525
refreshControl?: ?React.Element<any>,
529526
children?: React.Node,
530527
|}>;
@@ -598,8 +595,8 @@ class ScrollView extends React.Component<Props, State> {
598595
*/
599596
_scrollResponder: typeof ScrollResponder.Mixin = createScrollResponder(this);
600597

601-
constructor(...args) {
602-
super(...args);
598+
constructor(props: Props) {
599+
super(props);
603600

604601
/**
605602
* Part 2: Removing ScrollResponder.Mixin
@@ -617,6 +614,7 @@ class ScrollView extends React.Component<Props, State> {
617614
typeof ScrollResponder.Mixin[key] === 'function' &&
618615
key.startsWith('scrollResponder')
619616
) {
617+
// $FlowFixMe - dynamically adding properties to a class
620618
(this: any)[key] = ScrollResponder.Mixin[key].bind(this);
621619
}
622620
}
@@ -630,6 +628,7 @@ class ScrollView extends React.Component<Props, State> {
630628
Object.keys(ScrollResponder.Mixin)
631629
.filter(key => typeof ScrollResponder.Mixin[key] !== 'function')
632630
.forEach(key => {
631+
// $FlowFixMe - dynamically adding properties to a class
633632
(this: any)[key] = ScrollResponder.Mixin[key];
634633
});
635634
}
@@ -685,7 +684,7 @@ class ScrollView extends React.Component<Props, State> {
685684
}
686685
}
687686

688-
setNativeProps(props: Object) {
687+
setNativeProps(props: {[key: string]: mixed}) {
689688
this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
690689
}
691690

@@ -699,17 +698,18 @@ class ScrollView extends React.Component<Props, State> {
699698
...typeof ScrollView,
700699
...typeof ScrollResponder.Mixin,
701700
} {
701+
// $FlowFixMe - overriding type to include ScrollResponder.Mixin
702702
return ((this: any): {
703703
...typeof ScrollView,
704704
...typeof ScrollResponder.Mixin,
705705
});
706706
}
707707

708-
getScrollableNode(): any {
708+
getScrollableNode(): ?number {
709709
return ReactNative.findNodeHandle(this._scrollViewRef);
710710
}
711711

712-
getInnerViewNode(): any {
712+
getInnerViewNode(): ?number {
713713
return ReactNative.findNodeHandle(this._innerViewRef);
714714
}
715715

@@ -725,17 +725,23 @@ class ScrollView extends React.Component<Props, State> {
725725
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
726726
*/
727727
scrollTo(
728-
y?: number | {x?: number, y?: number, animated?: boolean},
729-
x?: number,
730-
animated?: boolean,
728+
options?: {x?: number, y?: number, animated?: boolean} | number,
729+
deprecatedX?: number,
730+
deprecatedAnimated?: boolean,
731731
) {
732-
if (typeof y === 'number') {
732+
let x, y, animated;
733+
if (typeof options === 'number') {
733734
console.warn(
734735
'`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
735736
'animated: true})` instead.',
736737
);
737-
} else {
738-
({x, y, animated} = y || {});
738+
y = options;
739+
x = deprecatedX;
740+
animated = deprecatedAnimated;
741+
} else if (options) {
742+
y = options.y;
743+
x = options.x;
744+
animated = options.animated;
739745
}
740746
this._scrollResponder.scrollResponderScrollTo({
741747
x: x || 0,
@@ -832,7 +838,7 @@ class ScrollView extends React.Component<Props, State> {
832838
}
833839
}
834840

835-
_handleScroll = (e: Object) => {
841+
_handleScroll = (e: ScrollEvent) => {
836842
if (__DEV__) {
837843
if (
838844
this.props.onScroll &&
@@ -859,16 +865,16 @@ class ScrollView extends React.Component<Props, State> {
859865
this._scrollResponder.scrollResponderHandleScroll(e);
860866
};
861867

862-
_handleLayout = (e: Object) => {
863-
if (this.props.invertStickyHeaders) {
868+
_handleLayout = (e: LayoutEvent) => {
869+
if (this.props.invertStickyHeaders === true) {
864870
this.setState({layoutHeight: e.nativeEvent.layout.height});
865871
}
866872
if (this.props.onLayout) {
867873
this.props.onLayout(e);
868874
}
869875
};
870876

871-
_handleContentOnLayout = (e: Object) => {
877+
_handleContentOnLayout = (e: LayoutEvent) => {
872878
const {width, height} = e.nativeEvent.layout;
873879
this.props.onContentSizeChange &&
874880
this.props.onContentSizeChange(width, height);
@@ -888,7 +894,7 @@ class ScrollView extends React.Component<Props, State> {
888894
let ScrollViewClass;
889895
let ScrollContentContainerViewClass;
890896
if (Platform.OS === 'android') {
891-
if (this.props.horizontal) {
897+
if (this.props.horizontal === true) {
892898
ScrollViewClass = AndroidHorizontalScrollView;
893899
ScrollContentContainerViewClass = AndroidHorizontalScrollContentView;
894900
} else {
@@ -911,10 +917,10 @@ class ScrollView extends React.Component<Props, State> {
911917
);
912918

913919
const contentContainerStyle = [
914-
this.props.horizontal && styles.contentContainerHorizontal,
920+
this.props.horizontal === true && styles.contentContainerHorizontal,
915921
this.props.contentContainerStyle,
916922
];
917-
if (__DEV__ && this.props.style) {
923+
if (__DEV__ && this.props.style !== undefined) {
918924
const style = flattenStyle(this.props.style);
919925
const childLayoutProps = ['alignItems', 'justifyContent'].filter(
920926
prop => style && style[prop] !== undefined,
@@ -966,7 +972,7 @@ class ScrollView extends React.Component<Props, State> {
966972
}
967973

968974
const hasStickyHeaders =
969-
stickyHeaderIndices && stickyHeaderIndices.length > 0;
975+
Array.isArray(stickyHeaderIndices) && stickyHeaderIndices.length > 0;
970976

971977
const contentContainer = (
972978
<ScrollContentContainerViewClass
@@ -999,14 +1005,15 @@ class ScrollView extends React.Component<Props, State> {
9991005
const DEPRECATED_sendUpdatedChildFrames = !!this.props
10001006
.DEPRECATED_sendUpdatedChildFrames;
10011007

1002-
const baseStyle = this.props.horizontal
1003-
? styles.baseHorizontal
1004-
: styles.baseVertical;
1008+
const baseStyle =
1009+
this.props.horizontal === true
1010+
? styles.baseHorizontal
1011+
: styles.baseVertical;
10051012
const props = {
10061013
...this.props,
10071014
alwaysBounceHorizontal,
10081015
alwaysBounceVertical,
1009-
style: ([baseStyle, this.props.style]: ?Array<any>),
1016+
style: [baseStyle, this.props.style],
10101017
// Override the onContentSizeChange from props, since this event can
10111018
// bubble up from TextInputs
10121019
onContentSizeChange: null,
@@ -1057,12 +1064,12 @@ class ScrollView extends React.Component<Props, State> {
10571064
pagingEnabled: Platform.select({
10581065
// on iOS, pagingEnabled must be set to false to have snapToInterval / snapToOffsets work
10591066
ios:
1060-
this.props.pagingEnabled &&
1067+
this.props.pagingEnabled === true &&
10611068
this.props.snapToInterval == null &&
10621069
this.props.snapToOffsets == null,
10631070
// on Android, pagingEnabled must be set to true to have snapToInterval / snapToOffsets work
10641071
android:
1065-
this.props.pagingEnabled ||
1072+
this.props.pagingEnabled === true ||
10661073
this.props.snapToInterval != null ||
10671074
this.props.snapToOffsets != null,
10681075
}),
@@ -1115,10 +1122,6 @@ class ScrollView extends React.Component<Props, State> {
11151122
}
11161123
}
11171124

1118-
const TypedScrollView = ((ScrollView: any): Class<
1119-
InternalScrollViewType<Props>,
1120-
>);
1121-
11221125
const styles = StyleSheet.create({
11231126
baseVertical: {
11241127
flexGrow: 1,
@@ -1137,4 +1140,4 @@ const styles = StyleSheet.create({
11371140
},
11381141
});
11391142

1140-
module.exports = TypedScrollView;
1143+
module.exports = ScrollView;

Libraries/Experimental/WindowedListView.js

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ class WindowedListView extends React.Component<Props, State> {
208208
return (
209209
this._scrollRef &&
210210
this._scrollRef.getScrollResponder &&
211+
// $FlowFixMe - it actually returns ScrollView & ScrollResponder.Mixin
211212
this._scrollRef.getScrollResponder()
212213
);
213214
}

Libraries/Types/CoreEventTypes.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ export type ScrollEvent = SyntheticEvent<
125125
y: number,
126126
x: number,
127127
|}>,
128-
zoomScale: number,
128+
zoomScale?: number,
129+
responderIgnoreScroll?: boolean,
129130
|}>,
130131
>;
131132

0 commit comments

Comments
 (0)