'Global Type Declarations within a NX and NextJS monorepo

I've been looking around the web to try and find s nice solution to my problem but so far I have not.

I have a NX monorepo with NextJS and I am trying to create a global types/ folder that can be used by all of my apps and libs.

I had thought this would be quite simple, I would add a folder to the root and put all my .d.ts files in there. Then in the tsconfig.base.json I would add

"typeRoots": [
  "node_modules/@types",
  "node_modules/next/types",
  "types/"
]

I was hoping it would be as simple as that.

Allowing me to use my typing anywhere within the monorepo without having to import them.

Unfortunately, this didn't work. After lots of messing around I did manage to get it to work but only if the types/ folder was inside of the app, for example:

apps/
    /myApp/
          /types/            <- types here were detected
types/                       <- types here were not detected
tsconfig.base.json

This is no good for me as it would mean I would have to duplicate my types across all apps and libs.

The official recommendation from NX is to add a new lib just to store your types and then import it and use it in each of your apps and libs but this feels really clunky to me. Also, this doesn't really work with the idea of adding it to typeRoots within the tsbase.config.json

If anyone knows a better way this can be done I would love to hear about it.

Cheers.



Solution 1:[1]

Battling with the same issue right now. So far, this works for my project, but it's still not an ideal solution. I would much rather have a global provider.

apps/
    /myApp/
          tsconfig.app.json
types/                       <- add your .d.ts files here
tsconfig.base.json

in the tsconfig.app.json of each app add the following:

"include": ["../../types/**/*.d.ts"]

This will import all the type definitions stored in the global folder. But the configuration still has to be handled manually in each library and app.

Let me know if this is helpful or if you have found a better solution.

Solution 2:[2]

I cracked this problem in my repo this way: In the tsconfig.base.json add "./types to "typeRoots".

"typeRoots": [..., "./types", ...]

Each type (in tsconfig "types") you want to reference should be in separate folder in index.d.ts file:

types/my-own-module/index.d.ts

Then you can add the typings to tsconfigs (tsconfig.lib.json, `tsconfig.app.json in each project:

"types": [..., "my-own-module", ...]

The only downside is, that you need to add the typings to each project you need, it does not work globally, because usually each project has different "types" config.

An untested idea is to remove "types" from all configs and just add all needed types into the global tsconfig.

Solution 3:[3]

I've found a simple solution... In the root of your project create your types.d.ts file.

For each app and library, in the tsconfig.app.json or tsconfig.lib.json add this to the "files" section:

"../../types.d.ts"

Screenshot example

Works for me with nx version 12.10.1

Solution 4:[4]

Below setup works fine for all apps but not libs...

I have index.d.ts in a root directory:


    // /index.d.ts
    declare global {
      namespace MyNamespace {
         interface MyInterface { ... }
      }
    }

In tsconfig.base.json I have added "esModuleInterop": true, and "typeRoots": ["index.d.ts"] in compilerOptions. Then in each /apps/my-app/tsconfg.json I added "../../index.d.ts" in include array.

This allows me to use global declarations in apps without the need to import anything.

const myVar: MyNamespace.MyInterface = ...

I tried to do the same for libs but it does not work.

There are three tsconfig.jsons in lib directory:

  • tsconfig.json (main)
  • tsconfig.lib.json (lib)
  • tsconfig.spec.json (spec)
  • and if i use a storybook for a lib then there is fourth /.storybook/tsconfig.json (storybook).

lib, spec and storybook configs extend main config.

There is error in the file:

Referenced project '/.../libs/shared-one/tsconfig.lib.json' must have setting "composite": true.

if i set composite to true for lib, spec, storybook configs then I get following error there:

Composite projects may not disable declaration emit.

What is wrong? How do I share global type declarations among nx libs? I hoped this will work out of the box.

example of tsconfig.lib.json (lib)


    {
      "extends": "./tsconfig.json",
      "compilerOptions": {
        "composite": true,
        "outDir": "../../dist/out-tsc",
        "types": ["node"]
      },
      "files": [
        "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
        "../../node_modules/@nrwl/react/typings/image.d.ts"
      ],
      "exclude": [
        "**/*.spec.ts",
        "**/*.spec.tsx",
        "**/*.stories.ts",
        "**/*.stories.js",
        "**/*.stories.jsx",
        "**/*.stories.tsx"
      ],
      "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
    }

/libs/my-lib tsconfig.json (main)

    {
      "extends": "../../tsconfig.base.json",
      "compilerOptions": {
        "jsx": "react-jsx",
        "allowJs": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
      },
      "files": [],
      "include": ["../../index.d.ts"],
      "references": [
        {
          "path": "./tsconfig.lib.json"
        },
        {
          "path": "./tsconfig.spec.json"
        },
        {
          "path": "./.storybook/tsconfig.json"
        }
      ]
    }

tsconfig.base.json: (base)


    {
      "compileOnSave": false,
      "compilerOptions": {
        "rootDir": ".",
        "sourceMap": true,
        "declaration": false,
        "moduleResolution": "node",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "importHelpers": true,
        "target": "es2015",
        "module": "esnext",
        "lib": ["es2017", "dom"],
        "skipLibCheck": true,
        "skipDefaultLibCheck": true,
        "baseUrl": ".",
        "paths": {
          "@my-org/shared-one": ["libs/shared-one/src/index.ts"],
          "@my-org/shared-two": ["libs/shared-two/src/index.ts"]
        }
      },
      "exclude": ["node_modules", "tmp"],
      "include": ["index.d.ts"]
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bernat Duran Pons
Solution 2
Solution 3
Solution 4 mtx