Back to Expo

Migrating [Universal Modules][universal-modules] to TypeScript

guides/Migrating Universal Modules to TypeScript.md

latest4.2 KB
Original Source

Migrating Universal Modules to TypeScript

Change Import

To optimize our libraries for dead code elimination we should migrate our exports to be imported as such:

diff

- import { FileSystem } from 'expo-file-system';

+ import * as FileSystem from 'expo-file-system/legacy';

Ideally we would make the main entry-point of a module be a file named like the module like build/FileSystem.js

package.json

diff
- "main": "index.js",

+ "main": "build/<MODULE NAME>.js",
+ "types": "build/<MODULE NAME>.d.ts",

To migrate from libraries using different imports, we should add a deprecation notice.

A lot of libraries are just import from Expo, in these cases we can just the deprecation. Ensure you change all imports across packages/, apps/, and docs/.

src/index.ts

ts
import * as FileSystem from './FileSystem';
export * from './FileSystem';

let wasImportWarningShown = false;
// @ts-ignore: Temporarily define an export named "FileSystem" for legacy compatibility
Object.defineProperty(exports, 'FileSystem', {
  get() {
    if (!wasImportWarningShown) {
      console.warn(
        `The syntax "import { FileSystem } from 'expo-file-system'" is deprecated. Use "import * as FileSystem from 'expo-file-system'" or import named exports instead. Support for the old syntax will be removed in SDK 34.`
      );
      wasImportWarningShown = true;
    }
    return FileSystem;
  },
});

Then eventually remove the index in favor of the named file. (src/FileSystem.ts)

Testing

Migration should include the addition of a src/__tests__ which can be run with yarn test in the root directory of the package.

  1. If the package is using the old structure of test/ for utilities, they should migrate to using jest-expo.

src/__tests__/<MODULE NAME>-test.ts

diff
- import { mockPlatformWeb } from '../../test/mocking';

+ import { mockPlatformWeb } from 'jest-expo';
  1. Add a jest object to the package.json

package.json

js
"jest": {
  "preset": "expo-module-scripts"
},
  1. Run yarn test to run the tests.

Add the tests to CI

In the root .circleci/config.yaml add a step to the job named expo_sdk. This should be in alphabetic order with the other testing steps.

.circleci/config.yaml

yaml
- yarn:
    command: test --maxWorkers 1
    working_directory: ~/expo/packages/expo-sms

Move native dependencies to peerDependencies

In order to prevent overlapping native code in node_modules, we should move any dependencies containing native code to peerDependencies.

Add module scripts

package.json

js
"scripts": {
    "build": "expo-module build",
    "clean": "expo-module clean",
    "test": "expo-module test",
    "prepare": "expo-module prepare",
    "prepublishOnly": "expo-module prepublishOnly",
    "expo-module": "expo-module"
}

Generate a tsconfig.json file with expo-module-scripts

To get the tsconfig that we use in all of our modules, run expo-module prepare or the yarn script yarn prepare (given the script is defined in a module's package.json)

/tsconfig.json

json
// @generated by expo-module-scripts
{
  "extends": "expo-module-scripts/tsconfig.base",
  "compilerOptions": {
    "outDir": "./build"
  },
  "include": ["./src"],
  "exclude": ["**/__mocks__/*", "**/__tests__/*"]
}

Various Other Changes

  • Remove babel-preset-expo
  • Remove flow
  • For reusing types across the web implementation's native layer and API layer, types should be moved to a named file with the .types.ts extension. There are cases (expo-av for example) where you should separate types into smaller files.