javascripttypescriptvite

Unable to get TypeScript to recognize file path aliases


I am trying to get file path aliases setup in a project. I've setup everything according to this article. Vite is able to resolve the path aliases, so I don't get any runtime errors. However, TypeScript keeps giving the following error whenever I try to import using a path alias: Cannot find module '@components/AppLayout' or its corresponding type declarations. ts(2307)

I've tried several different options for the paths, and have made sure to restart VSCode after each change. Can anyone tell what I am doing wrong?

Example import with TS errors

import AppLayout from '@components/AppLayout'
import HomePage from '@pages/HomePage'
import LoginPage from '@pages/LoginPage'

vite.config.js

/* eslint-disable import/no-extraneous-dependencies */
import path from 'path'

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vite.dev/config/
export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@assets': path.resolve(__dirname, './src/assets'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@pages': path.resolve(__dirname, './src/pages'),
      '@redux': path.resolve(__dirname, './src/redux'),
      '@types': path.resolve(__dirname, './src/types'),
      '@utils': path.resolve(__dirname, './src/utils'),
    },
  },
  plugins: [react()],
})

tsconfig.json

{
  "files": [],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@assets/*": ["src/assets/*"],
      "@components/*": ["src/components/*"],
      "@hooks/*": ["src/hooks/*"],
      "@pages/*": ["src/pages/*"],
      "@redux/*": ["src/redux/*"],
      "@types/*": ["src/types/*"],
      "@utils/*": ["src/utils/*"],
    },
  },
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

tsconfig.app.json

{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src"]
}

tsconfig.node.json

{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["vite.config.ts"]
}

Solution

  • I haven't yet found relevant documentation covering this specific scenario, but after some experimentation it seems like when using project references you need to specify paths and baseUrl in the referenced projects rather than in the referencer. Try moving paths and baseUrl to tsconfig.app.json and/or tsconfig.node.json.

    In general, projects are self-contained. A project defines its own configuration, and that configuration does not change when another project starts referencing it.

    See also this related question: Use of alias paths inside a referenced project