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.
@typescript-eslint/consistent-type-imports: Ensure that imports only used locally as types useimport type@typescript-eslint/consistent-type-exports(requires type information): Ensure that exports of types useexport type@typescript-eslint/no-import-type-side-effects(optional): If all specifiers in an import use inlinetypequalifiers (import { type a, type b } from 'foo') it will convert them toimport type(import type { a, b } from 'foo'). (This is helpful for preventing accidental side effect imports, especially withverbatimModuleSyntaxenabled.)@ms-cloudpack/eslint-pluginalso provides a config with these rules and some others enforcing Cloudpack-related best practices.
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.
isolatedModulesenforcesexport type, but it will only work once you've enabled allconst enumusage.verbatimModuleSyntaxenforcesimport 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-effectsto prevent accidental side effect imports.