I have a pretty large npm module written in TypeScript, which exposes a number of types, including several interfaces. Now these interfaces do not all make sense at the root level, which is why I would like to expose them in a way that they can be imported in a somewhat nested way.
Basically, I'm looking for a way to expose interface so that the user of the module can do:
import { Foo } from 'my-module';
import { Bar } from 'my-module/sub-part';
Is this possible in TypeScript, and if so, how? What does not work is this code in the root index.ts
file:
export {
Foo,
{ Bar }
};
Please note that the .ts
files are not located at the root directory of the module, and so the .js
and .d.ts
files aren't either.
How can I solve this?
PS: It's not about default vs named export here, since I want to have a solution for exporting interfaces in multiple nested levels.
In the easiest case, you just have separate index.d.ts
files inside the my-module
and my-module/sub-part
folder of the published npm package, so we can import my-module
and my-module/sub-part
separately. Example project directory:
my-module
| dist
│ index.ts
│ package.json // types prop e.g. could point to dist/index.d.ts
│
└───sub-part
index.ts // compiled to dist/sub-part/index.d.ts
TS makes use of its module resolution process to resolve my-module
or my-module/sub-part
imports (given no global type declaration like @types
exists). For example, my-module
in import { Foo } from 'my-module'
is resolved like this:
// first, try to find file directly
node_modules/my-module.ts
node_modules/my-module.tsx
node_modules/my-module.d.ts
// look in package.json for types property pointing to a file
node_modules/my-module/package.json // <-- lands here, if "types" prop exists
// look in @types
node_modules/@types/my-module.d.ts
// treat my-module as folder and look for an index file
node_modules/my-module/index.ts
node_modules/my-module/index.tsx
node_modules/my-module/index.d.ts // <-- lands here otherwise
For the sake of completness here, my-module
and my-module/sub-part
could also be defined as separate global module declarations in one containing file, like:
declare module "my-module" {
const Foo: string
}
declare module "my-module/sub-part" {
const Bar: number
}
Finally, the client code looks like you already pictured:
import { Foo } from "my-module";
import { Bar } from "my-module/sub-part";
console.log(Foo)
Hope, it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With