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
-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
 export class AssetService {
3
 export class AssetService {
5
   resolveFromRequire(value: ImageRequireSource) {
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
 
4
 
5
 let RNNElement: React.ComponentType<any>;
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
   static propTypes = {
8
   static propTypes = {
9
     elementId: PropTypes.string.isRequired,
9
     elementId: PropTypes.string.isRequired,
10
     resizeMode: PropTypes.string
10
     resizeMode: PropTypes.string
15
   };
15
   };
16
 
16
 
17
   render() {
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
 import { NativeModules } from 'react-native';
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
 export class NativeCommandsSender {
20
 export class NativeCommandsSender {
4
-  private readonly nativeCommandsModule;
21
+  private readonly nativeCommandsModule: NativeCommandsModule;
5
   constructor() {
22
   constructor() {
6
     this.nativeCommandsModule = NativeModules.RNNBridgeModule;
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
     return this.nativeCommandsModule.setRoot(commandId, layout);
27
     return this.nativeCommandsModule.setRoot(commandId, layout);
11
   }
28
   }
12
 
29
 

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

12
 import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';
12
 import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';
13
 
13
 
14
 export class NativeEventsReceiver {
14
 export class NativeEventsReceiver {
15
-  private emitter;
15
+  private emitter: { addListener(event: string, callback: any): EventSubscription };
16
   constructor() {
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
     try {
19
     try {
18
       this.emitter = new NativeEventEmitter(NativeModules.RNNEventEmitter);
20
       this.emitter = new NativeEventEmitter(NativeModules.RNNEventEmitter);
19
     } catch (e) {
21
     } catch (e) {

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

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

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

14
 
14
 
15
   beforeEach(() => {
15
   beforeEach(() => {
16
     const mockedAssetService = mock(AssetService);
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
     const assetService = instance(mockedAssetService);
23
     const assetService = instance(mockedAssetService);
19
 
24
 
20
     const mockedColorService = mock(ColorService);
25
     const mockedColorService = mock(ColorService);
60
     };
65
     };
61
     uut.processOptions(options);
66
     uut.processOptions(options);
62
     expect(options).toEqual({
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