question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

👻 Flow Typing NativeModules

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:51
  • Comments:66 (62 by maintainers)

github_iconTop GitHub Comments

18reactions
fkgozalicommented, Jun 1, 2019

As of https://github.com/facebook/react-native/commit/18fededae085b53b01e54a7ed27e32c2318e7cae, all 42 PRs have now been merged! Thank you for all the contributions to this effort!

I’ll close this issue for now.

6reactions
ericlewiscommented, May 16, 2019

We got 'em all i think

Read more comments on GitHub >

github_iconTop Results From Across the Web

Module Types | Flow
Importing and exporting types. It is often useful to share types in between modules (files). In Flow, you can export type aliases, interfaces,...
Read more >
max_split_size_mb stable diffusion - You.com | The Search Engine ...
facebook/react-native👻 Flow Typing NativeModules#24875. Created over 3 years ago ... Define flow types based on the NativeModule's native methods.
Read more >
Learn from 425 web development courses on egghead
In this course, you'll learn the fundamentals of Supabase. You'll learn how to model complex data using PostgreSQL and SQL, build authentication flows...
Read more >
react-native-iap - npm
This is a react-native native module library project for in-app purchase for both Android and iOS platforms.
Read more >
The new architecture is here… what now? - Speaker Deck
TURBOMODULES React JS Bundle Native UI Native Modules Metro JS* ... THE CODEGEN FLOW typed JS parser schema generated interfaces.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found