Skip to content

Repo guidance: Use consistent type imports and exports

Background

The tsconfig.json setting isolatedModules helps to enforce that packages can be transpiled correctly without parsing dependencies. This is where Cloudpack picks up a lot of performance: we rely on the ability to transpile things individually.

But enabling this can be a daunting task. It will provide errors when:

  • You use const enum. (See our guide for removing const enums to help get rid of them!)
  • You import type-only things like interfaces without annotating them with import type.
  • You export type-only things without annotating them with export type.

These last two issues become very important in transpilation when you import or export types from another library. Because the transpiler doesn't parse the other library, it leaves non-annotated imports and exports in the JS ESM output, causing a runtime error.

The fix is easy enough: change import { SomeInterface } from 'some-library' to be import type { SomeInterface } from some-library. Now do that for every single type imported or exported in your repo. Yikes, lots of work.

Migration using lint rules

TIP

For more details about these lint rules and their interaction with TypeScript settings, see this excellent typescript-eslint blog post.

Thankfully, @typescript-eslint/eslint-plugin has some rules that can help with migration. You can either use these for both migration and enforcement, or just run a one-time pass for migration and enforce with TS settings.

The consistent-type-exports rule is the only one that requires type information. If your repo is too slow to regularly lint with type information, you can enable typed linting locally and run the rule fixer to help with initial migration (using multiple subset passes if needed), then enforce with isolatedModules (see below).

After enabling these rules in your repo, run eslint --fix to auto fix all the imports and exports, and check it in. Some repos find it easier to do this in batches (only enable the rules locally, and check in batches of fixes).

Enforcement

You can either use the lint rules for continued enforcement, or use TypeScript settings. For each case (imports and exports), it's best to pick one or the other to avoid conflicts.

  • isolatedModules enforces export type, but it will only work once you've enabled all const enum usage.
  • verbatimModuleSyntax enforces import type.
    • Depending on your output settings, this rule may have some undesirable side effects (see the doc link for details). So in some repos, it may be preferable to leave the lint rule enabled instead.
    • With this setting, it's recommended to enable no-import-type-side-effects to prevent accidental side effect imports.