Browse Source

Road to implicitAny part 4 (#4497)

What is this?
This PR continues the work on making this project type safe with TypeScript. Goal is that the flag noImplicitAny will be set to true

What this PR does?
* all files inside adapter folder is valid for noImplicitAny!
* resolveAssetSource is now imported from the current place where it should. Previously it was imported from legacy location. More info here: https://facebook.github.io/react-native/docs/image#resolveassetsource
* formatted many files
* add missing interfaces
* fix onPressIn prop on TouchablePreview

What's next?
Next I am planning to make same treatment for commands folder and many it valid for noImplicitAny 🎉
Henrik Raitasola 6 years ago
parent
commit
02985c507a

+ 2
- 3
lib/src/adapters/AssetResolver.ts View File

@@ -1,8 +1,7 @@
1
-import * as resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
2
-import { ImageRequireSource } from 'react-native';
1
+import { ImageRequireSource, Image } from 'react-native';
3 2
 
4 3
 export class AssetService {
5 4
   resolveFromRequire(value: ImageRequireSource) {
6
-    return resolveAssetSource(value);
5
+    return Image.resolveAssetSource(value);
7 6
   }
8 7
 }

+ 6
- 12
lib/src/adapters/Element.tsx View File

@@ -4,7 +4,7 @@ import { requireNativeComponent } from 'react-native';
4 4
 
5 5
 let RNNElement: React.ComponentType<any>;
6 6
 
7
-export class Element extends React.Component<{ elementId: any; resizeMode?: any; }, any> {
7
+export class Element extends React.Component<{ elementId: any; resizeMode?: any }> {
8 8
   static propTypes = {
9 9
     elementId: PropTypes.string.isRequired,
10 10
     resizeMode: PropTypes.string
@@ -15,18 +15,12 @@ export class Element extends React.Component<{ elementId: any; resizeMode?: any;
15 15
   };
16 16
 
17 17
   render() {
18
-    return (
19
-      <RNNElement {...this.props} />
20
-    );
18
+    return <RNNElement {...this.props} />;
21 19
   }
22 20
 }
23 21
 
24
-RNNElement = requireNativeComponent(
25
-  'RNNElement',
26
-  Element,
27
-  {
28
-    nativeOnly: {
29
-      nativeID: true
30
-    }
22
+RNNElement = requireNativeComponent('RNNElement', Element, {
23
+  nativeOnly: {
24
+    nativeID: true
31 25
   }
32
-);
26
+});

+ 19
- 2
lib/src/adapters/NativeCommandsSender.ts View File

@@ -1,12 +1,29 @@
1 1
 import { NativeModules } from 'react-native';
2 2
 
3
+interface NativeCommandsModule {
4
+  setRoot(commandId: string, layout: { root: any; modals: any[]; overlays: any[] }): Promise<any>;
5
+  setDefaultOptions(options: object): void;
6
+  mergeOptions(componentId: string, options: object): void;
7
+  push(commandId: string, onComponentId: string, layout: object): Promise<any>;
8
+  pop(commandId: string, componentId: string, options?: object): Promise<any>;
9
+  popTo(commandId: string, componentId: string, options?: object): Promise<any>;
10
+  popToRoot(commandId: string, componentId: string, options?: object): Promise<any>;
11
+  setStackRoot(commandId: string, onComponentId: string, layout: object): Promise<any>;
12
+  showModal(commandId: string, layout: object): Promise<any>;
13
+  dismissModal(commandId: string, componentId: string, options?: object): Promise<any>;
14
+  dismissAllModals(commandId: string, options?: object): Promise<any>;
15
+  showOverlay(commandId: string, layout: object): Promise<any>;
16
+  dismissOverlay(commandId: string, componentId: string): Promise<any>;
17
+  getLaunchArgs(commandId: string): Promise<any>;
18
+}
19
+
3 20
 export class NativeCommandsSender {
4
-  private readonly nativeCommandsModule;
21
+  private readonly nativeCommandsModule: NativeCommandsModule;
5 22
   constructor() {
6 23
     this.nativeCommandsModule = NativeModules.RNNBridgeModule;
7 24
   }
8 25
 
9
-  setRoot(commandId: string, layout: { root: any, modals: any[], overlays: any[] }) {
26
+  setRoot(commandId: string, layout: { root: any; modals: any[]; overlays: any[] }) {
10 27
     return this.nativeCommandsModule.setRoot(commandId, layout);
11 28
   }
12 29
 

+ 3
- 1
lib/src/adapters/NativeEventsReceiver.ts View File

@@ -12,8 +12,10 @@ import {
12 12
 import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';
13 13
 
14 14
 export class NativeEventsReceiver {
15
-  private emitter;
15
+  private emitter: { addListener(event: string, callback: any): EventSubscription };
16 16
   constructor() {
17
+    // NOTE: This try catch is workaround for integration tests
18
+    // TODO: mock NativeEventEmitter in integration tests rather done adding try catch in source code
17 19
     try {
18 20
       this.emitter = new NativeEventEmitter(NativeModules.RNNEventEmitter);
19 21
     } catch (e) {

+ 19
- 19
lib/src/adapters/TouchablePreview.tsx View File

@@ -14,14 +14,21 @@ import {
14 14
 } from 'react-native';
15 15
 
16 16
 // Polyfill GestureResponderEvent type with additional `force` property (iOS)
17
-interface NativeTouchEventWithForce extends NativeTouchEvent { force: number; }
17
+interface NativeTouchEventWithForce extends NativeTouchEvent {
18
+  force: number;
19
+}
18 20
 interface GestureResponderEventWithForce extends NativeSyntheticEvent<NativeTouchEventWithForce> {}
19 21
 
20 22
 export interface Props {
21 23
   children: React.ReactNode;
22
-  touchableComponent?: TouchableHighlight | TouchableOpacity | TouchableNativeFeedback | TouchableWithoutFeedback | React.ReactNode;
24
+  touchableComponent?:
25
+    | TouchableHighlight
26
+    | TouchableOpacity
27
+    | TouchableNativeFeedback
28
+    | TouchableWithoutFeedback
29
+    | React.ReactNode;
23 30
   onPress?: () => void;
24
-  onPressIn?: (reactTag?) => void;
31
+  onPressIn?: (payload: { reactTag: number | null }) => void;
25 32
   onPeekIn?: () => void;
26 33
   onPeekOut?: () => void;
27 34
 }
@@ -30,8 +37,7 @@ const PREVIEW_DELAY = 350;
30 37
 const PREVIEW_MIN_FORCE = 0.1;
31 38
 const PREVIEW_TIMEOUT = 1250;
32 39
 
33
-export class TouchablePreview extends React.PureComponent<Props, any> {
34
-
40
+export class TouchablePreview extends React.PureComponent<Props> {
35 41
   static propTypes = {
36 42
     children: PropTypes.node,
37 43
     touchableComponent: PropTypes.func,
@@ -48,7 +54,7 @@ export class TouchablePreview extends React.PureComponent<Props, any> {
48 54
   static peeking = false;
49 55
 
50 56
   private timeout: number | undefined;
51
-  private ts: number = 0;
57
+  private touchStartedAt: number = 0;
52 58
   private onRef = React.createRef<any>();
53 59
   onPress = () => {
54 60
     const { onPress } = this.props;
@@ -79,13 +85,13 @@ export class TouchablePreview extends React.PureComponent<Props, any> {
79 85
 
80 86
   onTouchStart = (event: GestureResponderEvent) => {
81 87
     // Store a timstamp of the initial touch start
82
-    this.ts = event.nativeEvent.timestamp;
88
+    this.touchStartedAt = event.nativeEvent.timestamp;
83 89
   }
84 90
 
85 91
   onTouchMove = (event: GestureResponderEventWithForce) => {
86 92
     clearTimeout(this.timeout);
87 93
     const { force, timestamp } = event.nativeEvent;
88
-    const diff = (timestamp - this.ts);
94
+    const diff = timestamp - this.touchStartedAt;
89 95
 
90 96
     if (force > PREVIEW_MIN_FORCE && diff > PREVIEW_DELAY) {
91 97
       TouchablePreview.peeking = true;
@@ -111,21 +117,15 @@ export class TouchablePreview extends React.PureComponent<Props, any> {
111 117
     const { children, touchableComponent, onPress, onPressIn, ...props } = this.props;
112 118
 
113 119
     // Default to TouchableWithoutFeedback for iOS if set to TouchableNativeFeedback
114
-    const Touchable = (
115
-      Platform.OS === 'ios' && touchableComponent instanceof TouchableNativeFeedback
116
-        ? TouchableWithoutFeedback
117
-        : touchableComponent
118
-    ) as typeof TouchableWithoutFeedback;
120
+    const Touchable = (Platform.OS === 'ios' &&
121
+    touchableComponent instanceof TouchableNativeFeedback
122
+      ? TouchableWithoutFeedback
123
+      : touchableComponent) as typeof TouchableWithoutFeedback;
119 124
 
120 125
     // Wrap component with Touchable for handling platform touches
121 126
     // and a single react View for detecting force and timing.
122 127
     return (
123
-      <Touchable
124
-        ref={this.onRef}
125
-        onPress={this.onPress}
126
-        onPressIn={this.onPressIn}
127
-        {...props}
128
-      >
128
+      <Touchable ref={this.onRef} onPress={this.onPress} onPressIn={this.onPressIn} {...props}>
129 129
         <View
130 130
           onTouchStart={this.onTouchStart}
131 131
           onTouchMove={this.onTouchMove as (event: GestureResponderEvent) => void}

+ 12
- 4
lib/src/commands/OptionsProcessor.test.ts View File

@@ -14,7 +14,12 @@ describe('navigation options', () => {
14 14
 
15 15
   beforeEach(() => {
16 16
     const mockedAssetService = mock(AssetService);
17
-    when(mockedAssetService.resolveFromRequire(anyNumber())).thenReturn('lol');
17
+    when(mockedAssetService.resolveFromRequire(anyNumber())).thenReturn({
18
+      height: 100,
19
+      scale: 1,
20
+      uri: 'lol',
21
+      width: 100
22
+    });
18 23
     const assetService = instance(mockedAssetService);
19 24
 
20 25
     const mockedColorService = mock(ColorService);
@@ -60,9 +65,12 @@ describe('navigation options', () => {
60 65
     };
61 66
     uut.processOptions(options);
62 67
     expect(options).toEqual({
63
-      backgroundImage: 'lol',
64
-      rootBackgroundImage: 'lol',
65
-      bottomTab: { icon: 'lol', selectedIcon: 'lol' },
68
+      backgroundImage: { height: 100, scale: 1, uri: 'lol', width: 100 },
69
+      rootBackgroundImage: { height: 100, scale: 1, uri: 'lol', width: 100 },
70
+      bottomTab: {
71
+        icon: { height: 100, scale: 1, uri: 'lol', width: 100 },
72
+        selectedIcon: { height: 100, scale: 1, uri: 'lol', width: 100 }
73
+      }
66 74
     });
67 75
   });
68 76