Description
Search Terms
isolatedModules, type export, type re-export, babel
Context
In --isolatedModules
mode you get an error when reexporting types, the reason why this breaks is documented in the new handbook. In the following example lines 2 and 5 both raise give "Cannot re-export a type when the '--isolatedModules' flag is provided." warnings.
import { SomeType } from "someModule";
export { SomeType };
let x: SomeType | undefined;
export { SomeOtherType } from "someModule";
This leaves programme authors who wish to compile using a per-file compiler with some choices:
Use export * from "someModule"
, which will deal with all exports, but won't work if you need to cherry pick exports. It's usually possibly to rearchitect your folder structure to work around this but not always.
Or use a temporary renaming:
import { SomeType as SomeType1, SomeOtherType as SomeOtherType1 } from "someModule";
export type SomeType = SomeType1;
let x: SomeType | undefined;
export type SomeOtherType = SomeOtherType1;
Prior to #31231 (to be released in TS 3.7) authors could export a type that matches the same name as an import, but that loophole has been closed:
import { SomeType, SomeOtherType } from "someModule";
export type SomeType = SomeType;
let x: SomeType | undefined;
export type SomeOtherType = SomeOtherType;
Authors should not have to go through such renaming dances in order to get type reexports working in isolatedModules mode, instead it should be possible to hint that an import / reexport is of a type.
Suggestion
Add some kind of syntax hint to imports and reexports that denote that a particular identifier is a type and thus can be elided when compiling in isolatedModules mode.
Here I'm proposing the strawman of a type
keyword before the ImportSpecifier / ExportSpecifier, as suggested by @Jessidhia in #31231 (comment). This is the same syntax Flow uses though I must admit I'm not familiar with Flow.
import { type SomeType } from "someModule";
export { SomeType };
let x: SomeType | undefined;
export { type SomeOtherType } from "someModule";
Placing the hint on a per-specifier basis will allow mixing of type and value import/reexports in a single import/export statement:
import { SomeValue, type SomeType, SomeOtherValue, type SomeOtherType } from "someModule";
export { AnotherValue, type AnotherType, YetAnotherValue, type YetAnotherType } from "someOtherModule";
Regarding unhappy paths:
- Adding a
type
hint to a value should raise a type error "Value export must not be tagged as a type" - When isolatedModules is enabled type exports without a type hint should continue to raise a type error, though the message will likely need to be updated to something like "Cannot rexport type without a
type
hint" - When isolatedModules is disabled then there is no value to adding the
type
hint. We could disable adding the hints by throwing a TypeError "Type exports withtype
hint are only required in isolatedModules mode" but that feels pretty heavy handed. I think a better path is allowing the type hint from the compiler's perspective, while having a linting rule to that can can say if these type hints should be present or not (defaulting to present for isolatedModules is enabled and absent if disabled). This will help projects who wish to migrate from usingtsc
to a per-file compiler.
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.