Why doesn't the exports field of npm work in typescript?

Viewed 1002

Our library @ltonetwork/lto, is written in typescript. We use tsc to compile to javascript in the lib folder.

The package contains several sub-packages, which are located in subfolders that contain an index.ts file.

When trying to import a submodule, like this

import {Transfer} from "@ltonetwork/lto/transactions";

I'm expecting this to work, but I get the following error

test.ts:1:24 - error TS2307: Cannot find module '@ltonetwork/lto/transactions' or its corresponding type declarations.

The package.json of @ltonetwork/lto contains

{
  "scripts": {
    "compile": "tsc -p ./tsconfig.json"
  },
  "main": "lib",
  "exports": {
    ".": "./lib/index.js",
    "./*": "./lib/*/index.js",
    "./package.json": "./package.json"
  },
  "files": [
    "lib",
    "interfaces.d.ts"
  ]
}

and the tsconfig.json is

{
  "compilerOptions": {
    "alwaysStrict": true,
    "baseUrl": "",
    "lib": ["es2017.object", "es2015", "es6", "dom"],
    "module": "commonjs",
    "sourceMap": true,
    "declaration": true,
    "target": "es6",
    "paths": {},
    "rootDir": "src",
    "outDir": "lib"
  },
  "include": ["src"]
}

I've tried to explicitly name the submodules, instead of using wildcards in exports, but that made no difference.

What am I doing wrong that's causing this import issue?


Edit: This is not related to monorepos or yarn workspaces. This is about using the exports field in npm with typescript 4.7.1-rc. This feature wasn't working with earlier versions of typescript.

For more information see https://github.com/microsoft/TypeScript/issues/33079

I've also tried

{
  "scripts": {
    "compile": "tsc -p ./tsconfig.json"
  },
  "main": "lib",
  "exports": {
    ".": {
      "require": {
        "default": "./lib/index.js",
        "types": "./lib/index.d.ts"
      },
      "import": {
        "default": "./lib/index.js",
        "types": "./lib/index.d.ts"
      }
    },
    "./transactions": {
      "require": {
        "default": "./lib/transactions/index.js",
        "types": "./lib/transactions/index.d.ts"
      },
      "import": {
        "default": "./lib/transactions/index.js",
        "types": "./lib/transactions/index.d.ts"
      }
    },
    "./package.json": "./package.json"
  },
  "files": [
    "lib",
    "interfaces.d.ts"
  ]
}
2 Answers

Ensure moduleResolution in the consuming library is set to either Node16 or NodeNext in your tsconfig.json file.

Since Typescript 3.1 we've been able to do this and it doesn't require the consumer to have a tsconfig.json.

"typesVersions": {
    "*": {
        "path1": [ "./path/to/path1.d.ts" ],
        "path2": [ "./path/to/path2.d.ts" ],        
    }
},

This may only work with named submodules.

Related