sha256-uint8array icon indicating copy to clipboard operation
sha256-uint8array copied to clipboard

TypeScript cannot find .d.ts when using moduleResolution: NodeNext

Open NWilson opened this issue 1 year ago • 4 comments

I recently updated my tsconfig to use moduleResolution: NodeNext (which enables "exports" processing in package.json).

However, I am still producing CommonJS output using "module: NodeNext" in tsconfig with "type: commonjs".

This causes TypeScript to load the "require" branch in your exports, which has no typings:

"exports": {
    ".": {
      "require": "./lib/sha256-uint8array.js",
      "import": {
        "types": "./types/sha256-uint8array.d.ts",
        "default": "./dist/sha256-uint8array.mjs"
      }
    }
  },

You should export the typings for both require&import clients as follows:

"exports": {
    ".": {
      "types": "./types/sha256-uint8array.d.ts",
      "require": "./lib/sha256-uint8array.js",
      "import": "./dist/sha256-uint8array.mjs"
    }
  },

NWilson avatar Jun 17 '24 13:06 NWilson

@NWilson Thank you for the reporting. I've already almost forgotten the exact reasons but I guess the current complex tricky structrure of exports["."].import.types is made due to support another build system.

Hmm, found. Issue #3 made the change.

On your environment, the following plan B or C do work? (not tested on the environments though)

Plan B (types duplicated)

"exports": {
    ".": {
      "require": "./lib/sha256-uint8array.js",
      "types": "./types/sha256-uint8array.d.ts",
      "import": {
        "types": "./types/sha256-uint8array.d.ts",
        "default": "./dist/sha256-uint8array.mjs"
      }
    }
  },

Plan C (types duplicated and require/import separated)

"exports": {
    ".": {
      "require": {
        "types": "./types/sha256-uint8array.d.ts",
        "default": "./lib/sha256-uint8array.js"
      },
      "import": {
        "types": "./types/sha256-uint8array.d.ts",
        "default": "./dist/sha256-uint8array.mjs"
      }
    }
  },

kawanet avatar Jun 17 '24 15:06 kawanet

Wow, thanks for a quick reply!

I have tested plan A (my one) and it works.

I have tested your plan B, and it doesn't work, because the options listed are always tried first-to-last, and so because you put "require" before "types", the compiler just picks the "require" option and doesn't see the types. (However, it would work if you put "types" very first.)

I have tested your plan C, and works. To me, it seems equally correct & tidy as plan A. I have no preference or suggestion between A and C.

Thank you!

NWilson avatar Jun 17 '24 17:06 NWilson

@NWilson great! Could you give me your tsconfig.json or something? I could not reproduce the issue. I've tested it with https://github.com/kawanet/module-resolution-sandbox/blob/main/ts-esm/tsconfig.json

I recently updated my tsconfig to use moduleResolution: NodeNext (which enables "exports" processing in package.json). However, I am still producing CommonJS output using "module: NodeNext" in tsconfig with "type: commonjs".

kawanet avatar Jun 18 '24 01:06 kawanet

I have checked out your repo, and tested.

I have two changes compared to your ts-esm test:

  1. package.json has type: commonjs (yours has type: module, so TypeScript is loading the "import" field from sha256-uint8array, which is fine)
  2. tsconfig.json has strict: true (this is necessary to make TypeScript complain when it can't find the .d.ts)

NWilson avatar Jun 18 '24 13:06 NWilson