typescriptnpmvisual-studio-codemonoreponpm-workspaces

Typescript module import - no auto-completion in nested project architecture/npm-workspaces


I have a rather complex setup with many distributed npm packages, which require each other. I tried to break it down as much as possible. The setup looks like this (each subproject having its own package.json):

Project-root:
- package.json*
- /apps: - app1
         - app2
- /common
- /libs: - lib1
         - lib2

Apps: Each app is stand-alone and uses all libs and common, each having its own package.json

Common: Used for shared components, but only in apps (depends itself on all libs)

Libs: Private npm-packages used in other projects and in apps/common, WIP and therefore used/included via npm-workspaces/git clone. As they are added via npm install by workspaces

The problem I have is, that typescript/tsc is throwing error ts(2307) in all classes in "common"-module.

import { BarInterface } from '@mynamespace/lib1/foo';

Cannot find module '@mynamespace/lib1/foo' or its corresponding type declarations.

Everything works as desired and dev/build runs without errors, but Visual Studio Code/Intellisense and/or tsc is not capable to accept the provided import-statements in common. Therefor no auto-completion is available, which we highly rely on, as the project should be easy to get into for new developers.

* package.json (root):

{
  "name": "main-project",
  "workspaces": [
    "./apps/*",
    "./libs/*",
    "./common"
  ]    
}

* package.json (lib):

{
  "name": "@mynamespace/lib1",
  "exports": {
    "./foo": "./src/foo/index.ts",
  },   
}

* package.json (common):

{
  "name": "main-project-common",
  "exports": {
    "./bar": "./src/bar/index.ts",
  },
  "dependencies": { 
    "@mynamespace/lib1": "^1.0.0"
    "@mynamespace/lib2": "^1.0.0"
  }   
}

* package.json (app1):

{
  "name": "app1",
  "exports": {
    "./bar": "./src/bar/index.ts",
  },
  "dependencies": { 
    "@mynamespace/main-project-common": "file:../../common"
  }   
}

All tsconfig.json-files look like this:

{
  "compilerOptions": {
    "target": "es2018",
    "module": "esnext",
    "lib": ["es2017", "dom", "dom.iterable"],
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "./types",
    "rootDir": "./src",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": false,
    "resolveJsonModule": true,
    "noImplicitAny": false
  },
  "include": ["src/**/*.ts", "global.d.ts"],
  "exclude": []
}

vite.config.js

import { defineConfig } from 'vite';
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    target: 'esnext',
    lib: {
      entry: path.resolve(__dirname, 'src/index.ts'),
      formats: ['es'],
    },
    rollupOptions: {
      external: /^lit/,
    },
  },
});

Do I miss something or is the setup too complex or some kind of anti-pattern not supported by typescript?


Solution

  • I found the problem. I missed the module declaration of the common-module.

    Adding a file global.d.ts to /common with the following content solved the issue for me.

    declare module '*';
    

    This step is required for each typescript module.