14

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

jackieTruong123
  • 251
  • 1
  • 3
  • 7

8 Answers8

5

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"
}

deathangel908
  • 8,601
  • 8
  • 47
  • 81
4

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",
                         ....
                        
                    }
                }
            ]
        ]
    };
};


        }
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
3

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.

AndreyProgr
  • 537
  • 4
  • 14
  • 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. – jackieTruong123 Nov 27 '21 at 02:43
  • I'd also love to know why my config doesnt work and be looking forward to more practicle solutions – jackieTruong123 Nov 27 '21 at 02:46
  • interesting, but I think it will be a bit redundant if we can do it without `package.json` on every directory. – jted95 Nov 27 '21 at 03:10
  • 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. – AndreyProgr Nov 27 '21 at 05:17
  • 1
    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. – nima Mar 14 '22 at 09:11
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"
}

jted95
  • 1,084
  • 1
  • 9
  • 23
  • thank you, but it still not working... I've already cleared cache, restarted the metro server, typescript but still met no luck – jackieTruong123 Nov 27 '21 at 03:50
  • 1
    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 Nov 27 '21 at 04:04
  • @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. – jted95 Nov 27 '21 at 05:51
  • 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 – jackieTruong123 Nov 27 '21 at 14:42
  • I added my repository to the questions. If you dont mind, please take a look and help me, please. Thank you. – jackieTruong123 Nov 27 '21 at 15:02
  • @jackieTruong123 hey, I just tried to open that but it gave me 404 – jted95 Nov 28 '21 at 22:22
  • hi, so sorry for that. That project goes private now so you cant go inside. instead, you can check my new repository for that. Those 2 repos are having the same problem :| – jackieTruong123 Dec 03 '21 at 15:47
0

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

mirsahib
  • 375
  • 1
  • 4
  • 12
0

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"]
}

Ahmed Younes
  • 964
  • 12
  • 17
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"]
}
mehmetdemiray
  • 976
  • 4
  • 13
  • 32
0

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.
shehan chanuka
  • 71
  • 1
  • 10