20

so basically, I created my React Native with Typescript using the commandline in RN homepage: npx react-native init MyApp --template react-native-template-typescript

After that, I ran the project and it was built successfully. However, when I added the path alias to import my file, it threw an error: Unable to resolve module #folder/file from ... could not be found within the project or in these directories: node_modules

I've already followed some tutorials and bug resolves on Google but I've met no luck.

Here is my .babelrc file (I tried to change the file from babel.config.js to .babelrc as some resolver said but it still didn't work)

{
  "presets": ["module:metro-react-native-babel-preset"],
  "plugins": [
    [
      "module-resolver",
      {
        "root": ["./src"],
        "extensions": [
          ".js",
          ".jsx",
          ".ts",
          ".tsx",
          ".android.js",
          ".android.tsx",
          ".ios.js",
          ".ios.tsx"
        ],
        "alias": {
          "#src/*": [
            "./src/*"
          ],
          "#configs/*": [
            "./src/config/*"
          ],
          "#actions/*": [
            "./src/redux/actions/*"
          ],
          "#reducers/*": [
            "./src/redux/reducers/*"
          ],
          "#store/*": [
            "./src/redux/store/*"
          ]
        }
      }
    ]
  ]
}

tsconfig.json

{
  "compilerOptions": {
    /* Basic Options */
    "target": "esnext", 
    "module": "commonjs",
    "lib": [
      "ES2017",
      "DOM",
      "ES2015",
      "ES2015.Promise"
    ], 
    "allowJs": true, 
    "jsx": "react-native",
    "noEmit": true, 
    "incremental": true,
    "importHelpers": true,
    "isolatedModules": true,
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": ".", 
    "paths": {
      "#src/*": [
        "src/*"
      ],
      "#configs/*": [
        "src/config/*"
      ],
      "#actions/*": [
        "src/redux/actions/*"
      ],
      "#reducers/*": [
        "src/redux/reducers/*"
      ],
      "#store/*": [
        "src/redux/store/*"
      ]
    }, 
    "types": ["jest"],
    "allowSyntheticDefaultImports": true, 
    "esModuleInterop": true, 
    "skipLibCheck": false, 
    "resolveJsonModule": true 
  },
  "exclude": [
    "node_modules",
    "babel.config.js",
    "metro.config.js",
    "jest.config.js"
  ]
}

My folders and files structure

├───assets
├───components
├───config
│       constants.ts
│
└───redux
    ├───actions
    │       index.ts
    │       stateActions.ts
    │
    ├───reducers
    │       index.ts
    │       stateReducer.ts
    │
    └───store
            index.ts

Really looking forward to receive you guys answers. Thank you so much

P/s: if you dont mind, please take a look at my repository: https://github.com/NotJackieTruong/rn_test_typescript

2
  • 1
    Hi, did you find a solution to this? Commented Apr 6, 2022 at 18:19
  • 1
    @Thor0o0 the solution that worked for me was to remove /* from all of the aliases and directories. ¯\_(ツ)_/¯ Commented Nov 24, 2022 at 4:44

9 Answers 9

21

For expo v49+:

  1. module-resolver is not required, you can remove it from babel-config

  2. Add to app.json:

{
  "expo": {
    "experiments": {
      "tsconfigPaths": true
    }
  }
}
  1. Define paths as usual in tsconfig.json:
{
  "compilerOptions": {
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "extends": "expo/tsconfig.base"
}

Sign up to request clarification or add additional context in comments.

Comments

5

tsconfig.json

 "baseUrl": ".", 
 "paths": {
      
      // this is for src directory
      "@*": ["src/*"],
      "@configs/*": ["src/config/*"
      ],

babel.config.js

module.exports = function (api) {
    api.cache(true);
    return {
        presets: ["babel-preset-expo"],
        plugins: [
            [
                "module-resolver",
                {
                    alias: {
                        "@config": "./src/config",
                         ....
                        
                    }
                }
            ]
        ]
    };
};


        }

Comments

4

To make this work just need add package.json file to each directory you want to access with one property name in it. For example:

├───assets
└───components
    └───package.json

package.json content:

{
  "name": "components"
}

And then you can import like this:

import SomeComponent from 'components/SomeComponent';

There is also a good article describing how this works.

5 Comments

Thank you for your reply, but I have to add package.json to each directory every single time I add new components? It doesnt sound like a good method... But anyway, I appreciate your answer.
I'd also love to know why my config doesnt work and be looking forward to more practicle solutions
interesting, but I think it will be a bit redundant if we can do it without package.json on every directory.
From my experience I usually add package.json to several directories under source folder. For example assets, components, utils. These folders are very stable during whole project lifecycle.
I define a package.json in the root directories (under src directory) and it's working very well without any extra packages or configs. thank you.
4

In tsconfig.json


{
...
   "compilerOptions":{
        ...
       "baseUrl":"."
       "paths":{
            "@folder": "src/folder" <--assuming app logic is in src/ 
        }
   }
}

In babel.config.js

module.exports = {
...
  plugins: [
    ["module-resolver",{
      "alias":{
        "@folder": "./src/folder",
      }
    }]
  ],
};

Uninstall the app from emulator/device

Restart the metro server yarn start --reset-cache

Build the app yarn run android/ios

Comments

3

add this to your tsconfig.json

"include": ["./src/**/*"]

then restart your TypeScript Server

Cmd+Shift P then choose TypeScript: Restart TS server

Edit: this is the tsconfig.json I'm using if that helps

{
  "compilerOptions": {
    "noImplicitAny": true,
    "noEmit": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "react-native",
    "lib": ["es6", "dom", "esnext"],
    "moduleResolution": "node",
    "baseUrl": ".",
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "paths": {
      "@app/*": ["./src/*"]
    }
  },
  "include": ["src/**/*", "./App.tsx"],
  "extends": "expo/tsconfig.base"
}

7 Comments

thank you, but it still not working... I've already cleared cache, restarted the metro server, typescript but still met no luck
the weird thing is that when I import the file, vscode still recommends the right directory and when I click to it, it brings me to the right component.
@jackieTruong123 by right directory, does it use the path you specified in the config? btw, I put my tsconfig.json there for reference. I don't know why yours doesn't work, but let me know if you find the solution.
I tried to delete the paths or point to the wrong ones in the config file and it show import errors, so I assume that it uses my path specified in the typescript config
I added my repository to the questions. If you dont mind, please take a look and help me, please. Thank you.
|
2

In my case I was not using expo. I initiated my project using npx react-native init <App name>--template react-native-template-typescript. I ran into issues once I added path aliases to my .babelrc and tsconfig.js. I tries several instructions but nothing worked. My successful attempt was.

  1. Deleted node_modules and yarn.lock
  2. Converted babel.config.js into .babelrc. (Cannot gaurantee if this had to do with the success).
  3. Uninstalled the app from the emulator
  4. Ran yarn to install all the dependencies.
  5. Ran yarn start --reset-cache to install and run the app while removing the metro-cache.

Comments

1

For those who still stuck with the issue with all solutions you have just make sure the following:-

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

or

yarn add --dev babel-plugin-module-resolver

babel.config.js or .babelrc

make sure this is development not production in babel <<<<<<<<<<<<< VIP

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'],
  env: {
    development: { // <<< make sure this is development not production
      plugins: [
        'react-native-paper/babel',
        [
          'module-resolver',
          {
            root: ['./src'],
            extensions: [
              '.js',
              '.jsx',
              '.ts',
              '.tsx',
              '.android.js',
              '.android.tsx',
              '.ios.js',
              '.ios.tsx',
            ],
            alias: {
              '@hooks': ['./src/hooks'],
              '@familyway': ['./src'],
              '@assets': ['./src/Assets'],
              '@components': ['./src/Components'],
              '@constants': ['./src/Constants'],
              '@helpers': ['./src/helpers'],
              '@onboarding': ['./src/onBoarding'],
              '@redux': ['./src/redux'],
              '@screens': ['./src/Screens'],
              '@lib': ['./src/lib'],
              '@containers': ['./src/containers'],
            },
          },
        ],
      ],
    },
  },
};

ok now with the tsconfig.json


{
  "compilerOptions": {
    "target": "ES2022",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "esnext.asynciterable",
      "esnext.intl",
      "esnext.symbol",
      "esnext.array"
    ],
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "noImplicitAny": true,
    // "noImplicitReturns": true,
    // "noImplicitThis": true,
    "esModuleInterop": true,
    "alwaysStrict": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-native",
    "incremental": true,
    "noEmitOnError": true,
    "baseUrl": "./src",
    "paths": {
      "@hooks/*": ["hooks/*"],
      "@components/*": ["Components/*"],
      "@assets/*": ["Assets/*"],
      "@screens/*": ["Screens/*"],
      "@constants/*": ["Constants/*"],
      "@helpers/*": ["helpers/*"],
      "@onboarding/*": ["OnBoarding/*"],
      "@redux/*": ["redux/*"],
      "@containers/*": ["containers/*"],
      "@lib/*": ["lib/*"]
    }
  },
  "include": [
    "next-env.d.ts",
    "additional.d.ts",
    "src/**/*.ts",
    "src/**/*.js",
    "src/**/*.tsx",
    "./App.tsx",
    "./src/**/*",
    "src/**/*",
    "src/**/*.*"
  ],
  "exclude": ["node_modules"]
}

Comments

0

After long efforts and trials, I was able to make the path alias work with "@" as follows;

Note: My all codes in src directory.

babel.config.js

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'module-resolver',
      {
        root: ['./src'],
        alias: {
          '@': './src'
        }
      }
    ]
  ]
};

tsconfig.json

{
  "extends": "@tsconfig/react-native/tsconfig.json",
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@/*": ["*"]
    }
  },
  "include": ["src"]
}

Comments

0

I encountered this. I set alias @/ for src/* and everything worked well until I installed Redux Toolkit. I searched for 6 hours and turned out that the folder name redux is the root cause. Changing to src/store worked for me.

I used bare RN 0.77.0, @reduxjs/toolkit 2.5.1 and react-redux 9.2.0.

// tsconfig.json
{
  "extends": "@react-native/typescript-config/tsconfig.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

// babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    [
      'module-resolver',
      {
        root: ['./src'],
        extensions: [
          '.ios.ts',
          '.android.ts',
          '.ts',
          '.ios.tsx',
          '.android.tsx',
          '.tsx',
          '.jsx',
          '.js',
          '.json',
        ],
        alias: {
          '@': './src',
        },
      },
    ],
  ],
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.