node.js - `package.json` `exports`-feltet fungerer ikke med TypeScript


Versjon 13.2 av Node.js tillater ESM-moduler og et nytt package.json-felt, kalt exports, for å velge og omskrive eksporterte filer.

Før 13.2 importerte jeg filer fra dist-mappen i biblioteket mitt med:

import myfile from 'mylibrary/dist/myfile'

Med 13.2 la jeg dette til i min package.json:

exports: {
    "./": "./dist/"
}

Og prøvde å importere filer med:

import myfile from 'mylibrary/myfile'

Men Typescript gir 2307-feilen, og sier at modulen ikke finnes.

Svar #1

Det har endelig blitt tilgjengelig i Typescript 4.7

Biblioteket ditt:

// package.json
"exports": {
  ".": "./dist/index.js",
  "./svg": "./dist/svg.js",
  "./html": "./dist/html.js",
  "./package.json": "./package.json"
},

Klientkoden din må ha:

// tsconfig.json
"compilerOptions": {
  "moduleResolution": "node16" // or "nodenext"
}

Før Typescript 4.7 kunne du bruke typesVersions:

// package.json
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
  ".": "./dist/index.js",
  "./svg": "./dist/svg.js",
  "./html": "./dist/html.js",
  "./package.json": "./package.json"
},
"typesVersions": {
  "*": {
    "svg": ["dist/svg.d.ts"],
    "html": ["dist/html.d.ts"]
  }
}

Svar #2

TypeScript 4.7+ fullstendig løsning

Det nåværende beste svaret var ikke nok for meg - jeg fikk følgende feil når jeg prøvde å bruke biblioteket i en pakke som har modul: bundler.

feil TS7016: Kunne ikke finne en deklarasjonsfil for modul X, modul X har implisitt typen 'any'. Det finnes typer ved X, men dette resultatet kunne ikke løses når man respekterer package.json "exports". X-biblioteket kan trenge å oppdatere sin package.json eller typings.

Den fullstendige definisjonen i package.json krever en typerdeklarasjon i eksportene. Videre, hvis du leverer både ESM og CommonJS, må du bruke en egen typerdefinisjonsfil (av en ukjent grunn) - jeg løste dette ved å bruke rollup-plugin-copy

package.json

  ...
  "main": "./dist/index.common.js",
  "module": "./dist/index.mjs",
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.mts",
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.common.js"
      }
    }
  },
  "types": "./dist/index.d.ts",
  ...

types og module er valgfrie, for gammelt støtte. main er sannsynligvis også valgfri hvis eksportene er definert, hvis package.json type ikke er definert som 'module', så bør det være Common.js, ellers ESM. Merk også at det er å foretrekke å bruke .mjs-utvidelse for moduler, det finnes også cjs-utvidelse for CommonJS (og .d.cts) men vanlig .js er fint og er mest bakoverkompatibelt.

Merk at betingelsen "types" alltid bør komme først i "exports". [0]

Hvis du bruker Rollup, kan du bruke rollup-plugin-copy for å kopiere deklarasjonsfilen:

rollup.config.mjs

import copy from 'rollup-plugin-copy';

export default [
  // ...
  {
    // ...
    plugins: [
      // ...     
      copy({
        targets: [
          { src: 'dist/index.d.ts', dest: 'dist', rename: 'index.d.mts' },
        ],
      }),
    ]
  }
];

Denne hjelpen kan også være nyttig for å sikre at du får dette riktig.

[0] https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/

Svar #3

For alle andre som snubler over dette etter en tilsynelatende uendelig odyssé av frustrasjon og forvirring:

Viktig:
Node Package-importer støttes kun når moduleResolution er satt til "nodenext" eller "node16".

  • tsconfig.json
{
  "compilerOptions": {
    //                  ∨
    "moduleResolution": "nodenext"
    // <... config>
  }
}

Hvis det er satt, vil det fungere uten problemer. Et eksempel på hvordan dette kan se ut i et prosjekt:

  • package.json
{
  "type": "module",
  "imports": {
    "#util.define": "./src/util/define.ts"
    // <... etc.>
  }
  // <... config>
}
  • main.ts
import * as define from '#utils.define'

class Main {
  static {
    define.symbol(Main.prototype, Symbol.toStringTag, "Main")
  }
  // <... etc.>
}

Relaterte artikler