6

I have a Typescript library that is being consumed from a React app. I wanted to import the TS library contents with sub-paths like

import {base} from "my-lib"
import {foo} from "my-lib/path1"
import {bar} from "my-lib/path2"

I came across the Github issue which states that this is not yet supported (exports in package.json) by Typescript. I'm using Typescript 4.3.

There is a workaround posted in the same thread - Github repo typescript-subpath-exports-workaround. It uses exports and typeVersions

{
  "main": "dist/index.js",
  "types": "dist-types/index.d.ts",
  "exports": {
    ".": "./dist/index.js",
    "./exported": "./dist/exported.js"
  },
  "typesVersions": {
    "*": {
      "exported": ["dist-types/exported"]
    }
  }
}

I created a new react app (via npx create-react-app command) and tried importing hello from typescript-subpath-exports-workaround and it worked fine. But couldn't import `typescript-subpath-exports-workaround/exported

import {hello} from "typescript-subpath-exports-workaround" //works fine
import {foo} from "typescript-subpath-exports-workaround/exported" //gives "Module not found" error

Full error is below:

./src/App.js
Module not found: Can't resolve 'typescript-subpath-exports-workaround/exported' in '/Users/...../my-react-app/src'

Codesandbox code - https://codesandbox.io/s/create-react-app-forked-5yxd8

UPDATE: The sub-path used in import and the folder structure are different. In the above example, there won't be a folder named path1 or path2.

Ahmet Emre Kilinc
  • 5,489
  • 12
  • 30
  • 42
Thiyagu
  • 17,362
  • 5
  • 42
  • 79

3 Answers3

0

This block in my package.json worked for me:

{
    // ...
    "files": [
        "/dist"
    ],
    "main": "./dist/index.js",
    "types": "./dist/index.d.ts",
    "exports": {
        ".": "./dist/index.js",
        "./types": "./dist/types/index.js",
        "./generate": "./dist/generate/index.js"
    },
    "typesVersions": {
        "*": {
            "types": [
                "./dist/types/index.d.ts"
            ],
            "generate": [
                "./dist/generate/index.d.ts"
            ]
        }
    }
}

My tsconfig.json looks like this:

{
    "extends": "@tsconfig/node14/tsconfig.json",
    "include": ["src/**/*"],
    "compilerOptions": {
        "lib": ["es2020", "dom"],
        "declaration": true,
        "outDir": "dist",
        "module": "ESNext"
    }
}

And this is my file structure:

package.json
tsconfig.json
dist/ // and all its subfolders
src/
  generate/
    index.ts
  types/
    index.ts
  index.ts

Separately, I'm using TypeScript 4.7.4. Supposedly the exports field is supported with this version, but it didn't work for me. But this (maybe overly complex) workaround worked for me.

tqmai
  • 21
  • 3
-1

Look at the Next.JS React Framework. You can see that they use exactly the same approach as you have described. You can create a simple typescript application with their CLI tool like this:

npx create-next-app@latest --typescript

Then pay attention on imports used for instance in ./pages/index.tsx.

Then if you'll look into the ./node_modules/next/package.json you will see that they expose built files in two ways: actual code and type defs are inside ./node_modules/next/dist/* and their re-exports are right in ./node_modules/next/*.

At least this is a real-life example and a good place to start your experiments. It doesn't mean you have to learn the whole their codebase. You just need to mimic the essencial parts of their package.json file (https://github.com/vercel/next.js/blob/canary/packages/next/package.json), specifically main, types and files in your Typescript library.

Update

Just look where absent imports could be imported from:

enter image description here

As you might understand, those are the places, where corresponding *.d.ts files are placed. So you just need to create reexport files in the root folder of you library and mention them in 'files' property of your lib's package.json.

The exactly similar picture I have for my own library.

I think there is no other way to impement imports of your lib the way you want, except of having either reexports or original type definitions right in the lib's root folder

Ruslan Zhomir
  • 842
  • 9
  • 27
  • I believe the imports will work only when the folder structure is the same (say `next/dynamic`). In my project, the folder structure and the import path will be different. – Thiyagu Oct 20 '21 at 13:07
  • Well, you can use the similar approach with reexports to have the files of your lib where you want them to be, and at the same time, where they should be to let application import them they way you want. See an update to my answer – Ruslan Zhomir Oct 20 '21 at 13:38
  • Thanks. It looks promising. I will take a look – Thiyagu Oct 21 '21 at 17:06
-3

As answered in How to create a local module in TypeScript:

Using module-alias package might solve your problem.

Add this configuration below into package.json:

"_moduleAliases": {    "my-module":
"<your_build_folder>/modules/my-module" },

And this code on first line

of your main file (server.ts/index.ts)

import 'module-alias/register';

Shivam Jha
  • 3,160
  • 3
  • 22
  • 36