Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃懟 Flow Typing NativeModules #24875

Closed
RSNara opened this issue May 16, 2019 · 65 comments

Comments

@RSNara
Copy link
Contributor

commented May 16, 2019

Flow Typing NativeModules

The TurboModule system is nearly feature-complete on both Android and iOS. Before we rollout the system, we'd like to migrate all our OSS NativeModules to use it. As a prerequisite for this migration, all the the NativeModules must have spec files. There are currently 41 NativeModules in total, so there is a bunch of work to do. We'd love to use this as an opportunity to help get more people involved by contributing to React Native.

Instructions

  1. Pick an unclaimed module and comment that you're working on it.
  2. Create a Spec file called NativeXYZ.js, where XYZ is the name of the NativeModule.
  3. Define flow types based on the NativeModule's native methods.
  4. Change call-sites from NativeModules.XYZ to NativeXYZ
  5. Make sure flow passes
  6. Do one module per PR

What is a Spec file?

A Spec file looks like this:

NativeAnalytics.js

/**
 * Copyright 2004-present Facebook. All Rights Reserved.
 *
 * @flow strict-local
 * @format
 */

'use strict';

import type {TurboModule} from 'RCTExport';
import * as TurboModuleRegistry from 'TurboModuleRegistry';

export interface Spec extends TurboModule {
  +getConstants: () => {|
    constant1: string,
    constant2: boolean,
  |};
  +logCounter: (key: string, value: number) => void;
  +logEvent: (eventName: string, data: Object, analyticsModule: ?string) => void;
  +logRealtimeEvent: (
    eventName: string,
    data: Object,
    analyticsModule: ?string,
  ) => void;
}

export default TurboModuleRegistry.getEnforcing<Spec>(
  'Analytics',
);

Observations

  • We use TurboModuleRegistry.getEnforcing<Spec>('Analytics') as opposed to NativeModules.Analytics to require the NativeModule. TurboModuleRegistry.getEnforcing is an indirection that allows us to require both NativeModules and TurboModules. It throws if the NativeModule isn't there. In the case that a NativeModule is platform-specific, please use Platform.OS and conditionally call TurboModuleRegistry.getEnforcing.
  • Each Spec file exports an interface called Spec that extends TurboModule. This interface contains typings for methods exposed by the NativeModule/TurboModule.
  • NativeModule constants are declared in the return type of the getConstants() method. The old way of accessing constants as properties on NativeModule objects is deprecated and unsupported by the TurboModule system. On iOS, these constants map to the return type of constantsToExport in iOS and getConstants in Android.
  • Each Spec file is named Native*.js. The filename matters because our codegen uses it to name the generated Java interfaces, ObjC protocols, and C++ TurboModule subclasses. NativeAnalytics.js, for instance, will generate a Java interface and ObjC protocol called NativeAnalyticsSpec, and a C++ TurboModule class called NativeAnalyticsSpecJSI. After these Spec files are typed, we'll generate and check in the codegen output into this repository. Then, after we open source our codegen, we'll delete the generated interfaces, protocols, and C++ classes from this repository.
    • Note that the naming convention used here is not finalized, but stable enough for the time being.
  • This isn't a ViewManager. We're currently not focusing on ViewManagers. Therefore, there's no need to write spec files for them.
  • We're not using imported types. Our codegen doesn't support imported types. So, for the time being, all types used by the spec must be declared in the same file.

Supported Types

  • Methods with simple args:
    • string
    • boolean
    • number
    • Object
    • Array<*>*
  • Function and typed function:
    • Methods with nullable args
    • ?string
    • ?Object
    • ?Array<*>*
    • ?Function and nullable typed function
    • number and boolean are not supported
  • Methods with inline complex Object typed args
    • e.g. (x: {|foo: string, ... |}) => void
  • Methods that return a Promise<*>*
  • Synchronous methods that return simple non-nullable types
    • string
    • number
    • boolean
    • Object
    • Array<*>*
  • Optional methods with all variants above
  • Typed exported constants
  • Note: Flow unions aren't supported

How do you type NativeModules?

You have to deduce the types by looking at the NativeModule implementations on iOS and Android. Some NativeModules already have JS wrappers, so you could also look at those for writing the Spec files.

Guidelines

  • How do you know which methods are exported to JS?

    • On Android: Look for NativeModule non-inherited class methods annotated with @ReactMethod.
    • On iOS: Look for NativeModule non-inherited and inherited class methods wrapped in RCT_EXPORT_*_METHOD macros .
  • How do you know when a method should have a Promise return type?

    • On Android: The last argument of the method is the Promise object.
    • On iOS: The last two arguments are a RCTPromiseResolveBlock and RCTPromiseRejectBlock
  • What should the JS method name be?

    • On Android: It's the name of the Java method.
    • On iOS: It's the part of the selector before the first argument/color.
  • NSDictionary on iOS, and ReadableMap and WritableMap on Android translate to object literals in JS.

  • RCTResponseSenderBlock and RCTResponseErrorBlock on iOS, and Callback on Android translate to function literals in JS.

  • Try to avoid using Function and Object whenever possible.

  • In the case that a method or constant is unavailable on one platform, make it optional.

  • In the case that a NativeModule is unavailable on one platform, make it optional.

  • Where do you put the Spec file?

    • Most NativeModules belong to a Library (see the JS section of the table below), so you could write the Spec in the library. For the other NativeModules, write the spec inside react-native-github/Libraries/NativeModules/specs.

Platform-specific NativeModules

For platform-specific NativeModules, use Platform.OS to conditionally call TurboModuleRegistry.getEnforcing<Spec>. When changing the call-sites of these NativeModules, you may have to guard them with null checks to please flow.

Call-site Before

const NativeModules = require('NativeModules');
const IntentAndroid = NativeModules.IntentAndroid;

function foo() {
  if (Platform.OS === 'android') {
    IntentAndroid.method();
  }
}

Call-site After

const NativeIntentAndroid = require('NativeIntentAndroid');
const {Platform} = require('react-native');

function foo() {
  if (Platform.OS === 'android') {
    if (NativeIntentAndroid != null) {
      NativeIntentAndroid.method();
    }
  }
}

NativeModule List

Please claim a NativeModule from the list below.

猬滐笍 - Unclaimed
馃毀 - Claimed / PR in progress
- PR Merged

Status JS Name JS NativeModule Wrappers iOS Android
AccessibilityInfo react-native-github/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js AccessibilityInfoModule.java
AccessibilityManager react-native-github/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js RCTAccessibilityManager.m
AlertManager react-native-github/Libraries/Alert/Alert.js RCTAlertManager.m
AnimationDebugModule AnimationsDebugModule.java
AppState react-native-github/Libraries/AppState/AppState.js RCTAppState.m AppStateModule.java
BlobModule react-native-github/Libraries/Blob/BlobManager.js RCTBlobManager.mm BlobModule.java
DatePickerAndroid react-native-github/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js DatePickerDialogModule.java
DevLoadingView react-native-github/Libraries/Utilities/HMRLoadingView.ios.js RCTDevLoadingView.m
DevSettings N/A RCTDevSettings.mm DevSettingsModule.java
DeviceEventManager N/A DeviceEventManagerModule.java
DeviceInfo react-native-github/Libraries/Utilities/DeviceInfo.js RCTDeviceInfo.m DeviceInfoModule.java
DialogManagerAndroid N/A DialogModule.java
ExceptionsManager react-native-github/Libraries/Core/ExceptionsManager.js RCTExceptionsManager.m ExceptionsManagerModule.java
FileReaderModule N/A RCTFileReaderModule.m FileReaderModule.java
HeadlessJsTaskSupport N/A HeadlessJsTaskSupportModule.java
I18nManager react-native-github/Libraries/ReactNative/I18nManager.js RCTI18nManager.m I18nManagerModule.java
ImageEditor N/A RCTImageEditingManager.m ImageEditingModule.java
ImageStore N/A RCTImageStoreManager.m ImageStoreManager.java
IntentAndroid react-native-github/Libraries/Linking/Linking.js IntentModule.java
JSCHeapCapture react-native-github/Libraries/Utilities/HeapCapture.js JSCHeapCapture.java
JSCSamplingProfiler react-native-github/Libraries/Performance/SamplingProfiler.js JSCSamplingProfiler.java
JSDevSupport react-native-github/Libraries/Utilities/JSDevSupportModule.js JSDevSupport.java
KeyboardObserver react-native-github/Libraries/Components/Keyboard/Keyboard.js (NativeEventEmitter) RCTKeyboardObserver.m
LinkingManager react-native-github/Libraries/Linking/Linking.js RCTLinkingManager.m
ModalManager N/A RCTModalManager.m
NativeAnimatedModule react-native-github/Libraries/Animated/src/NativeAnimatedHelper.js RCTNativeAnimatedModule.m NativeAnimatedModule.java
Networking react-native-github/Libraries/Network/RCTNetworking.android.js RCTNetworking.mm NetworkingModule.java
react-native-github/Libraries/Network/RCTNetworking.ios.js
PermissionsAndroid react-native-github/Libraries/PermissionsAndroid/PermissionsAndroid.js PermissionsModule.java
PlatformConstants react-native-github/Libraries/Utilities/Platform.android.js RCTPlatform.m AndroidInfoModule.java
react-native-github/Libraries/Utilities/Platform.ios.js
RedBox N/A RCTRedBox.m
SettingsManager react-native-github/Libraries/Settings/Settings.ios.js RCTSettingsManager
SourceCode react-native-github/Libraries/Share/Share.js RCTSourceCode.m SourceCodeModule.java
TVNavigationEventEmitter react-native-github/Libraries/Components/AppleTV/TVEventHandler.js RCTTVNavigationEventEmitter.m
TimePickerAndroid react-native-github/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js TimePickerDialogModule.java
react-native-github/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
Timing react-native-github/Libraries/Core/Timers/JSTimers.js RCTTiming.m Timing.java
ToastAndroid react-native-github/Libraries/Components/ToastAndroid/ToastAndroid.android.js ToastModule.java
UIManager RCTUIManager.m UIManagerModule.java
WebSocketModule react-native-github/Libraries/WebSocket/WebSocket.js RCTWebSocketModule.m WebSocketModule.java

@RSNara RSNara self-assigned this May 16, 2019

@RSNara RSNara changed the title Flow Typing NativeModules 馃懟 Flow Typing NativeModules May 16, 2019

@ericlewis

This comment has been minimized.

Copy link
Collaborator

commented May 16, 2019

@RSNara any examples on how to handle event emitter classes?

@fkgozali

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

any examples on how to handle event emitter classes?

export interface Spec extends TurboModule {
  +getConstants: () => {|
    // any constants it exports
  |};

  // add any exported methods

  // Then add these 2 methods:

  // Events
  +addListener: (eventName: string) => void;
  +removeListeners: (count: number) => void;
}

eric: I changed the comment for listeners to be generic

@ericlewis

This comment has been minimized.

Copy link
Collaborator

commented May 16, 2019

Also worth noting: there are some places in the code base that directly access constants in JS, they need to be changed to be grabbed from getConstants.

Example:

const DeviceInfo = require('./DeviceInfo');
dims = DeviceInfo.Dimensions;

becomes:

const DeviceInfo = require('./DeviceInfo');
dims = DeviceInfo.getConstants().Dimensions;

luckily, flow will complain about these if you do your typing right! So, just update the callsites.

@michalchudziak

This comment has been minimized.

Copy link
Collaborator

commented May 16, 2019

Hey! I'd like to help with Linking module.

@gedeagas

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

Hi, I would like to help with DeviceInfo

@fkgozali

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

@michalchudziak, @gedeagas both were done by &ericlewis鈥 PRs

@fkgozali

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

PermissionAndroid/TimePickerAndroid are still open I think

@Krizzu

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

I'll go with PermissionsAndroid then

@michalchudziak

This comment has been minimized.

Copy link
Collaborator

commented May 16, 2019

Sure, no problem! Is it possible to work on AccessibilityManager & AccessibilityInfo?

Edit: I'm working on it :)

@wojteg1337

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

I work on ToastAndroid

@thymikee

This comment has been minimized.

Copy link
Collaborator

commented May 16, 2019

Taking Networking

@jeanregisser

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

Working on Timing

@jeanregisser

This comment has been minimized.

Copy link
Contributor

commented May 16, 2019

Working on WebSocketModule

@chakrihacker

This comment was marked as resolved.

Copy link

commented May 16, 2019

Taking ToastAndroid someone already taken

pull bot pushed a commit to Pandinosaurus/react-native that referenced this issue May 23, 2019

Add spec for AnimatedModule (facebook#24911)
Summary:
Part of facebook#24875. Added `strict-local` to the NativeModuleHelper btw.

## Changelog

[General] [Added] - TM add spec for AnimatedModule
Pull Request resolved: facebook#24911

Reviewed By: rickhanlonii

Differential Revision: D15434114

Pulled By: fkgozali

fbshipit-source-id: ea9215306ebf969795ce755270b8fdc14c52da9c

facebook-github-bot added a commit that referenced this issue May 23, 2019

Add spec for DialogManagerAndroid (#24912)
Summary:
Part of #24875.

## Changelog

[General] [Added] - TM add spec for DialogManagerAndroid
Pull Request resolved: #24912

Reviewed By: fkgozali

Differential Revision: D15433854

Pulled By: RSNara

fbshipit-source-id: e7234debe16de5afbc770f8feee2471f41b54427

facebook-github-bot added a commit that referenced this issue May 28, 2019

Add spec for AlertManager (#24906)
Summary:
Part of #24875

## Changelog

[General] [Added] - Add TurboModule spec for AlertManager
Pull Request resolved: #24906

Reviewed By: lunaleaps

Differential Revision: D15471065

Pulled By: fkgozali

fbshipit-source-id: bb22e6454b1f748987f3a8cd957bfd4e027493a5

facebook-github-bot added a commit that referenced this issue May 28, 2019

Add Spec for ImageEditor (#24921)
Summary:
This PR solves part of this issue: #24875
## Changelog

[General] [Added] - TM Spec for ImageEditor
Pull Request resolved: #24921

Reviewed By: rickhanlonii

Differential Revision: D15471058

Pulled By: fkgozali

fbshipit-source-id: f01539fc8acea95fca27ce7bb4b4169ffe138d93

facebook-github-bot added a commit that referenced this issue May 29, 2019

Add specs for ModalManager (#24896)
Summary:
Part of #24875

## Changelog
[General] [Added] - Add TurboModule spec for ModalManager
Pull Request resolved: #24896

Reviewed By: rickhanlonii

Differential Revision: D15471097

Pulled By: fkgozali

fbshipit-source-id: 99671583ddc2a6fc32fd1bcf9a6e340ad93a27c2

facebook-github-bot added a commit that referenced this issue May 29, 2019

Add spec for AccessibilityManager (#24894)
Summary:
Part of #24875

## Changelog

[General] [Added] - Add TurboModule spec for AccessibilityManager
Pull Request resolved: #24894

Reviewed By: rickhanlonii

Differential Revision: D15471243

Pulled By: fkgozali

fbshipit-source-id: 33f39d41d70da9380f29f2eb47e8c7682b323030
@fkgozali

This comment has been minimized.

Copy link
Contributor

commented May 29, 2019

It looks like ImageStore got left out. For anyone interested, feel free to claim it.

@mitulsavani

This comment has been minimized.

Copy link
Contributor

commented May 29, 2019

I hereby claim for it.

fkgozali referenced this issue May 29, 2019

Add spec for DeviceInfo module
Summary: Adding flow types for DeviceInfo module and migrating our codebase over to using `DeviceInfo.getConstants()`

Reviewed By: fkgozali

Differential Revision: D14645744

fbshipit-source-id: e30a060c6dc92938cd1420ba11a1d837c79d1e32

facebook-github-bot added a commit that referenced this issue May 30, 2019

add spec for PermissionsAndroid (#24886)
Summary:
Part of #24875

## Changelog
[General] [Added] - Add TurboModule spec for PermissionsAndroid
Pull Request resolved: #24886

Reviewed By: RSNara

Differential Revision: D15542996

Pulled By: fkgozali

fbshipit-source-id: cab02d97e70d65347f63e891cff98c17adc1fdba

facebook-github-bot added a commit that referenced this issue May 30, 2019

Add spec for Settings (#24879)
Summary:
part of #24875. I again, am not completely sure how the call site here works- appears settings can be directly accessed?

## Changelog

[General] [Added] - Add TM spec for Settings
Pull Request resolved: #24879

Reviewed By: RSNara

Differential Revision: D15543012

Pulled By: fkgozali

fbshipit-source-id: a1df3096a2fc5fe8e65d0ed2398912530bd3911a

facebook-github-bot added a commit that referenced this issue May 30, 2019

Add spec for AndroidToast (#24888)
Summary:
part of #24875

## Changelog

[General] [Added] - Add TM spec for AndroidToast
Pull Request resolved: #24888

Reviewed By: RSNara

Differential Revision: D15543043

Pulled By: fkgozali

fbshipit-source-id: 6636dd913f7c006704ead1aa92d37e42a4edf70e

facebook-github-bot added a commit that referenced this issue May 30, 2019

Add spec for Networking (#24892)
Summary:
Part of #24875, adds a spec for Networking. Since `sendRequest` methods are different for both platforms, I had to create 2 spec files as Flow would merge their definitions even when I added `Platform.OS` check

## Changelog

[General] [Added] - TM spec for Networking
Pull Request resolved: #24892

Reviewed By: RSNara

Differential Revision: D15543067

Pulled By: fkgozali

fbshipit-source-id: 2b91114dfa45e7899bbb139656a30a6fd52e31db
@fkgozali

This comment has been minimized.

Copy link
Contributor

commented May 30, 2019

DevSettings was also left out, feel free to claim.

@jarvisluong

This comment has been minimized.

Copy link
Contributor

commented May 30, 2019

I will claim the 鈥楧evSetting鈥

pull bot pushed a commit to SimenB/react-native that referenced this issue May 30, 2019

Add spec for WebSocketModule (facebook#24893)
Summary:
Part of facebook#24875

## Changelog

[General] [Added] - Add TurboModule spec for WebSocketModule
Pull Request resolved: facebook#24893

Reviewed By: RSNara

Differential Revision: D15551329

Pulled By: fkgozali

fbshipit-source-id: 59a921c50cc162528b2181fdd4cb1e41e3f1f6eb

pull bot pushed a commit to SimenB/react-native that referenced this issue May 30, 2019

add spec for PlatformConstants (facebook#24928)
Summary:
part of facebook#24875.

## Changelog

[General] [Added] - add TM spec for PlatformConstants
Pull Request resolved: facebook#24928

Reviewed By: RSNara

Differential Revision: D15551340

Pulled By: fkgozali

fbshipit-source-id: 9de15ff4cfe717f963332868bd873d5147a37506

facebook-github-bot added a commit that referenced this issue May 31, 2019

Add spec for UIManager (#24902)
Summary:
part of #24875. Because some of the methods are rewriteable, I dropped the `+` from the signature, this doesn't feel right to me, but I am not sure if the codegen requires that. If it does, it will probably be better to extend the spec and allow those specific methods to be overriden in a UIManager.js interface. Thoughts on that fkgozali or RSNara?

## Changelog

[General] [Added] - Add TM spec for UIManager
Pull Request resolved: #24902

Reviewed By: hramos

Differential Revision: D15551356

Pulled By: fkgozali

fbshipit-source-id: 076c4ce635aa7ea41e21cbd67c47ecd562fc320d

facebook-github-bot added a commit that referenced this issue May 31, 2019

Add spec for DevSettings (#25084)
Summary:
Part of #24875, adds a spec for DevSettings.

## Changelog

[General] [Added] - TM spec for DevSettings
Pull Request resolved: #25084

Reviewed By: hramos

Differential Revision: D15558093

Pulled By: fkgozali

fbshipit-source-id: 3adcb640a6ad80c84c831905bda114e27177f1fe

fkgozali referenced this issue May 31, 2019

Reland "[react-native][PR] [TM] Add spec for UIManager"
Summary: Original commit changeset: dff59dc9c98b

Reviewed By: JoshuaGross

Differential Revision: D15579147

fbshipit-source-id: 77a58d2ab3324e243610c1a4d4ab794a7095b3ee

fkgozali referenced this issue May 31, 2019

Reland "[react-native][PR] [TM] Add spec for DevSettings"
Summary: Original commit changeset: 70b4842f5cde

Reviewed By: cpojer

Differential Revision: D15578852

fbshipit-source-id: 6389a6f5ed2115182d88dcc777e6457c376750f6

facebook-github-bot added a commit that referenced this issue Jun 1, 2019

add spec for ImageStore (#25101)
Summary:
This PR solves part of this issue: #24875

## Changelog

[General] [Added] - add TM spec for ImageStore
Pull Request resolved: #25101

Reviewed By: hramos

Differential Revision: D15583463

Pulled By: fkgozali

fbshipit-source-id: 17e87e8fecb35d42a981b1fb348e40d2b1e91cc6

facebook-github-bot added a commit that referenced this issue Jun 1, 2019

add spec for I18nManager (#24908)
Summary:
Part of #24875.

## Changelog

[General] [Added] - add TM spec for I18nManager
Pull Request resolved: #24908

Reviewed By: fkgozali

Differential Revision: D15395163

Pulled By: RSNara

fbshipit-source-id: 8fd3a5a8ce5d0f74132efff4fae7224eab03405b
@fkgozali

This comment has been minimized.

Copy link
Contributor

commented Jun 1, 2019

As of 18feded, all 42 PRs have now been merged! Thank you for all the contributions to this effort!

I'll close this issue for now.

@fkgozali fkgozali closed this Jun 1, 2019

facebook-github-bot added a commit that referenced this issue Jun 26, 2019

TM iOS: Move generated specs for OSS NativeModules to github
Summary:
Note: iOS only.

This spec file (.h/.mm) was generated via FB internal codegen tool for TurboModule. The tool itself is not yet ready to be opensourced, but at least the generated file is. The output is based on all the Flow types added via #24875.
This file can be used by each ObjC NativeModule to be TurboModule compliant.

Reviewed By: rickhanlonii

Differential Revision: D15978911

fbshipit-source-id: 9e97495287bc406e0ed0ccf89cf370753b538772
@fkgozali

This comment has been minimized.

Copy link
Contributor

commented Jun 26, 2019

In order to get a sense of how the codegen output looks like, b1bf133 checked them in, based on all the Flow types you all have added. This is not used yet, and we're working on migrating each module to use it gradually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can鈥檛 perform that action at this time.