Updated June 9, 2022

How to Setup Path Alias in a React Native TypeScript App

So you've got a React Native app, you're using TypeScript, and you're being killing by long package imports. Let's fix that.

Take the project structure below - if I want to import CircleButton in components from my StopWatch.tsx in screens it's going to look like this:

import { CircleButton } from '../../components/buttons';

/Users/spencer/Dev/ClockApp
├── App.tsx
├── app.json
├── babel.config.js
├── package.json
├── src
|  ├── components
|  |  ├── buttons
|  |  |  ├── CircleButton.tsx
|  |  |  └── index.tsx
|  ├── index.tsx
|  └── screens
|     └── Clocks
|        └── StopWatch.tsx
├── tsconfig.json
└── yarn.lock

Let's fix that so your import statement can look like

import { CircleButton } from 'components/buttons';

or better yet

import { CircleButton } from 'buttons';

To accomplish this you need to update two files.

TypeScript Path Alias

The first is tsconfig.json. This is for TypeScript to understand the path alias.

First set your baseUrl to ., which represents the root of the directory. Every path in your tsconfig will be relative to that.

You then add your path alias' to the paths object. I'm going to add one for the components directory (components/buttons) and a direct one to the button exports (buttons).

// tsconfig.json
{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    // Path alias config
    "baseUrl": ".",
    "paths": {
      // This needs to be mirrored in babel.config.js
      // Components is a directory with sub directories
      "components/*": ["src/components/*"],

      // We want to expose the exports of the buttons index file
      "buttons": ["src/components/buttons/index"]
    }
  }
}

That will allow TypeScript to parse the following:

import { CircleButton } from "components/buttons"
import { CircleButton } from "buttons"

React Native Path Alias

Now we need to handle React Native path alias so the packager knows where to actually grab the files.

First install the babel-plugin-module-resolver as a developer dependency

yarn add --dev babel-plugin-module-resolver
npm install babel-plugin-module-resolver --save-dev

Now we can update the babel.config.js file to use the module-resolver plugin and point to our directories.

// babel.config.js

module.exports = function (api) {
  api.cache(true)
  return {
    presets: ["babel-preset-expo"],
    plugins: [
      [
        "module-resolver",
        {
          alias: {
            // This needs to be mirrored in tsconfig.json
            components: "./src/components",
            buttons: "./src/components/buttons",
          },
        },
      ],
    ],
  }
}

And you're all set! Now you can shorten your imports, type less, ease refactoring, and make it easier to scan code.

Pro tip: Want to use absolute paths but don't want to add an alias for every directory? Add your root directory (such as src) to the alias config as well!

// tsconfig.json

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    // Path alias config
    "baseUrl": ".",
    "paths": {
      // This needs to be mirrored in babel.config.js
      "components/*": ["src/components/*"],
      "buttons": ["src/components/buttons/index"],
      "src/*": ["src/*"]
    }
  }
}
// babel.config.js

module.exports = function (api) {
  api.cache(true)
  return {
    presets: ["babel-preset-expo"],
    plugins: [
      [
        "module-resolver",
        {
          alias: {
            // This needs to be mirrored in tsconfig.json
            components: "./src/components",
            buttons: "./src/components/buttons",
            src: "./src",
          },
        },
      ],
    ],
  }
}

Now you can use imports like import { CircleButton } from "src/components/buttons" as well.

Hope that helps!

React Native School Logo

React Native School

Want to further level up as a React Native developer? Join React Native School! You'll get access to all of our courses and our private Slack community.

Learn More