Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upType-only imports and exports #35200
Conversation
f26046a
to
d5e3ebb
|
@andrewbranch what about imported values that are only used for their types via |
|
@ajafff I think ideally the plan would be no, imports not marked with Of course, a workaround is to export a type alias from the file where the value was exported and import that instead, but you can’t do that if the value in question comes from a third party library. Edit: a surefire workaround is |
elektronik2k5
commented
Jan 5, 2020
|
This is an awesome and long awaited feature! @johnnyreilly and anyone else who needs this feature today without waiting for type SomeType = import('path-or-package').SomeExportedType
// or inline:
function(foo: import('path-or-package').SomeExportedType) { /* function body */ } |
johnnyreilly
commented
Jan 5, 2020
|
@elektronik2k5 I saw your thread on twitter! Thanks for sharing; somehow that had passed me by! |
|
Is it possible to import types from Example:import type Foo from "@types/foo";
import type { Bar } from "@types/bar";This would be particularly useful for importing types from non‑npm |
|
@ExE-Boss can you not already do this by simply leaving off the |
|
Well, I mean, you can, but it feels a bit weird to import types from a package that doesn’t provide any exports (and might not even exist at runtime). |
|
I think adding the |
…e fixes Summary: * Add private-named instance fields. Ex: `x.#name;`. [1] * Support type-only imports and exports. [2] * Improve the detection of conditional expressions `a ? b : c`. Allow multiple lines. * Add rules of round brackets `()` to correct the highlighting of pairs of brackets. [3] [1] microsoft/TypeScript#30829 [2] microsoft/TypeScript#35200 [3] https://unix.stackexchange.com/questions/527268/kate-18-12-3-no-longer-shows-matching-parenthesis-for-typescript Reviewers: #framework_syntax_highlighting, dhaumann, cullmann Reviewed By: #framework_syntax_highlighting, cullmann Subscribers: kwrite-devel, kde-frameworks-devel Tags: #kate, #frameworks Differential Revision: https://phabricator.kde.org/D27692


andrewbranch commentedNov 19, 2019
•
edited
TL;DR:
import type { A } from './mod',export type { A } from './mod'To do:
getTypeAtLocation)--importsNotUsedAsValue=errorerrorBackground
TypeScript elides import declarations from emit where, in the source, an import clause exists but all imports are used only in a type position [playground]. This sometimes creates confusion and frustration for users who write side-effects into their modules, as the side effects won’t be run if other modules import only types from the side-effect-containing module (#9191).
At the same time, users who transpile their code file by file (as in Babel, ts-loader in
transpileOnlymode) sometimes have the opposite problem, where a re-export of a type should be elided, but the compiler can’t tell that the re-export is only a type during single-file transpilation (#34750, TypeStrong/ts-loader#751) [playground].Prior art
In early 2015, Flow introduced type-only imports which would not be emitted to JS. (Their default behavior, in contrast to TypeScript’s, was never to elide imports, so type-only imports for them were intended to help users cut down on bundle size by removing unused imports at runtime.)
Two months later, #2812 proposed a similar syntax and similar emit behavior for TypeScript: the compiler would stop eliding import declarations from emit unless those imports were explicitly marked as type-only. This would give users who needed their imports preserved for side effects exactly what they wanted, and also give single-file transpilation users a syntactic hint to indicate that a re-export was type-only and could be elided:
export type { T } from './mod'would re-export the typeT, but have no effect on the JavaScript emit.#2812 was ultimately declined in favor of introducing the
--isolatedModulesflag, under which re-exporting a type is an error, allowing single-file transpilation users to catch ambiguities at compile time and write them a different way.Since then
Over the last four years after #2812 was declined, TypeScript users wanting side effects have been consistently confused and/or frustrated. They have workarounds (read #9191 in full for tons of background and discussion), but they’re unappealing to most people.
For single-file transpilation users, though, two recent events have made their lives harder:
In TypeScript 3.7, we sort of took away
--isolatedModulesusers’ best workaround for reexporting a type in #31231. Previously, you could replaceexport { JustAType } from './a'withBut as of TypeScript 3.7, we disallow the name collision of the locally declared
JustATypewith the imported nameJustAType.If a Webpack user was left with an erroneous
export { JustAType } from './a'in their output JavaScript, Webpack 4 would warn, but compilation would succeed. Many users simply ignored this warning (or even filtered it out of Webpack’s output). But in Webpack 5 beta, @sokra has expressed some desire to make these warnings errors.Proposal
Change the default emit behavior of the compiler to stop eliding regular imports even if the imported names are only used in type positionsAdd a (temporary?) compiler flag that restores the current behavior of eliding imports that are used only for types to help users with back-compat--importsNotUsedAsValue <"remove" | "preserve" | "error">to control the behaviorremoveis default; maintains today’s behaviorpreservekeeps imports used only for types in the emit as a side-effect importerroracts aspreservebut also adds an error whenever animportcould be written as animport typeSyntax
Supported forms are:
Possible additions but I think not terribly important:
We notably do not plan to support at this time:
typemodifier on import/export specifiers:import { type A } from './mod',export { A, type B }import type T, { A } from './mod',import type T, * as ns from './mod'The forms in the former bullet will be syntax errors; the forms in the latter will be grammar errors. We want to start with productions that can be read unambiguously, and it’s not immediately clear (especially in the absence of Flow’s implementation), what the semantics of
import type A, { B } from './mod'should be. Doestypeapply only to the default importA, or to the whole import clause? We prefer no one need wonder.Type semantics
Any symbol with a type side may be imported or exported as type-only. If that symbol has no value side (i.e., is only a type), name resolution for that symbol is unaffected. If the symbol does have a value side, name resolution for that symbol will see only the type side. The typical example is a class:
If the symbol is a namespace, resolution will see a mirror of that namespace recursively filtered down to just its types and namespaces:
Emit
Updated: When the
importsNotUsedAsValueflag is set to 'preserve', type-only import declarations will be elided. Regular imports where all imports are unused or used only for types will not be elided (only the import clause will be elided):Back-compat
flagThere’s a new flagremoveUnusedImports. Its name is not perfect because it really means “remove imports that have imported names that never get used in a value position.” Open to suggestions.Updated: this PR is backward-compatible by default.
Auto-imports behavior
I’m not yet confident what other changes, if any, will the right move, but the main scenarios to consider are:
Successor of #2812
Closes #9191
Closes #34750
Would close if they were still open: