Skip to main content

Type Safety

A Tale of Two Type Systems

React Native is built on JavaScript, which does not have a type system. This is a problem, because React Native is a large, complex platform. Without a type system, developers can't easily reason about the source code or use static analysis tools to find bugs.

When developers at Meta created React Native, they chose their own type system named Flow. Many open-source projects at Meta use Flow. It is part of their engineering system and culture. Flow is not used much outside of Meta.

The JavaScript community has largely embraced TypeScript. This includes the React Native developer community as well. React Native applications are written in TypeScript. Integrations with React Native -- plugins, presets, templates, etc -- are also written in TypeScript.

The tools in this project are written in TypeScript, too. Further, tools in this project which perform type-checking do so using the TypeScript language.

Platform-Specific Code

React Native introduces the concept of platform-specific extensions so that developers can write per-platform code in their applications. Platform-specific extensions require a specialized module resolver, capable of matching a module import to a file such as <module>.ios.js or <module>.native.js. Metro, the React Native bundler, has a resolver which supports this.

TypeScript version 4.7 also supports style of module resolution via the compiler option moduleSuffixes. See the announcement for details.

Module Substitution

React Native is implemented on many platforms which span several NPM packages. ios and android implementations are in the react-native NPM package, which is maintained by Meta. windows is under react-native-windows and macos is under react-native-macos, both of which are maintained by Microsoft. win32 is an Office-specific platform under @office-iss/react-native-win32.

windows, macos, and win32 are all considered to be out-of-tree platforms because they aren't part of the core react-native distribution. Each platform package is a complete implementation of React Native, and has (or should have) associated TypeScript types.

To avoid having "forked" references to the various NPM package names in code, developers are encouraged to always use import 'react-native'. Metro, the React Native bundler, substitutes 'react-native' with the target platform's out-of-tree NPM package. For macOS, import 'react-native' becomes import 'react-native-macos'.

We are working with the TypeScript team to support a similar "module substitution" mechanism for type-checking and IntelliSense.

TypeScript support is most beneficial when integrated with an editor like VSCode. Seeing platform-specific type-safety errors, during development, helps keep bugs out of the shared source tree.

This feature continues to be a work in progress.

Type-Safe Bundling

Metro, the React Native bundler, supports TypeScript source files, but it only transpiles them to JavaScript. Metro does not do any type-checking.

Our CLI combines Metro and TypeScript to solve this problem. Through configuration, you can enable type-checking while running the rnx-bundle and rnx-start commands. Warnings and errors from TypeScript appear on the console:

Unused function with missing type information
function foo(x) {
return x + 2;
Image showing TypeScript errors. Foo is declared but never used. Parameter x implicitly has an 'any' type.

The Bundling guide shows you how to enable type-safe bundling.