Home:ALL Converter>Best way to expose types to consumers when using typescript to create libraries/packages?

Best way to expose types to consumers when using typescript to create libraries/packages?

Ask Time:2018-12-04T03:45:04         Author:Xin Chen

Json Formatter

I've been searching and reading related information on this for a while, but still cannot get my head around this.

When I create a library or package using typescript, I like to set declaration to true so that when ts compiler compiles the source code, it will automatically generate declaration files for me. A typical library or package usually has an entry file and a bunch of files dependent with each other. So the outputs for the build result would look like this:

.
├── build
|   ├── entry.js (or entry.min.js in production)
|   ├── entry.d.ts (it depends on moduleA)
|   ├── moduleA.d.ts (it depends on moduleB)
|   ├── moduleB.d.ts
|   ├── types.d.ts (contains shared types for every body)
|   └── util.d.ts (declarations for some random util functions)

In package.json, I would just set this:

{
  ...
  "main": "./build/entry.js",
  "types": "./build/entry.d.ts",
  ...
}

The problem is even though entry.js has all the APIs I would like to expose to consumers, entry.d.ts doesn't have all the types I would like to also expose. That's because even though entry.ts has imports from types.ts, the type declarations will not be automatically imported from it. The consumer may want to use some enums I kept in types.ts (thus types.d.ts), which is not in entry.ts (thus entry.d.ts).

One way to use the types is to re-export it in the entry file, something like:

export * from './types';
// or
export { EnumA } from './types';

Which will allow consumer to do this:

import * as types from 'mylib';
// or 
import { EnumA } from 'mylib';

This is what I am doing right now, which is more of a manual workflow and there is a good chance that I forget to export some types that a consumer actually needs to use my library. I could just put all of my types/interfaces/enums in one single types.ts file and export everything, but I am not sure if that's the right thing to do.

typescript team is using namespaces to handle this (for example, server types and service types), but IMO that is redundant as we are already using ES6 modules. More on that in this post great cup example for explaining namespaces with modules.

Another workaround of this is to let consumer do

import * as types from 'mylib/build/types'

But IMO this is also a bad practise since we are essentially exposed implementation details to consumers, which we may change in the future.

I also want to add to above that if I want to generate library for ES5 codes with commonjs or AMD structure, the typescript offical document says to use export =. Apparently, this will prevent you from using export * from './types' anymore so the above workarounds will not working anymore.

That's where I am right now. Any suggestions? Right now I am leaning towards to use namespace like what typescript teams does, but I would like to hear more thoughts.

Author:Xin Chen,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/53600799/best-way-to-expose-types-to-consumers-when-using-typescript-to-create-libraries
yy