-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type-only import specifiers #45998
Type-only import specifiers #45998
Conversation
…while adding a specifier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looked fine to me and I could follow the code. The comments really helped understand what was going on. Just left some minor comments on possible typos.
Also didn't have time to review importFixes.ts
and some of the tests, but like I said, the rest looks good to me.
// import { type } from "mod"; - isTypeOnly: false, name: type | ||
// import { type as } from "mod"; - isTypeOnly: true, name: as | ||
// import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type | ||
// import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooof, this is awful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have completion list tests for these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tests for type
and then completions working as usual after a type
. After that, I don’t think you should get any completions, since the remaining things you type are / could be new identifier definitions... which I guess should still be tested ideally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good; would be nice to get some of the suggestions and tests in.
We will have to update other tooling teams on this (e.g. eslint, Babel, esbuild, swc, others). We also might want to think about these for dts-downlevel (@sandersn).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some ideas on the parser
let checkIdentifierStart = scanner.getTokenPos(); | ||
let checkIdentifierEnd = scanner.getTextPos(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aside: since these are only used for the error span, it would be nice for their names to contain "error".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good (as far as I understand auto imports at least).
!!! related TS1376 /c.ts:1:10: 'as' was imported here. | ||
|
||
==== /d.ts (3 errors) ==== | ||
import { type as as as as } from "./mod.js"; // Error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🦬 🦬 🦬 🦬
!!! error TS2300: Duplicate identifier 'as'. | ||
|
||
==== /e.ts (1 errors) ==== | ||
import { type type as as } from "./mod.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🦬 🦬 🐃🐃
Update: getting the keyword |
+1 we should consider refactoring the completions code before working on more completion features/not-so-small changes. |
Will this change mean that |
Nope. That would be an error only under the combination of |
Follow-up feature to #44619, allows
Emit behavior
type
keyword before an import or export specifier causes it to be elided from JS emit.type
keyword on an import or export specifier plays no direct role in whether the parent import/export declaration is elided.This means that under default settings,
gets erased from the JS entirely, because default settings remove any import declarations that can be removed. But under
--importsNotUsedAsValues=preserve
(orerror
), the same code is emitted asbecause the
type
keyword on the imports specifier does not indicate that there is no runtime module dependency on"./component"
.Auto-imports behavior
As discussed in #44619, the combination of
--isolatedModules
and--preserveValueImports
requires that exported symbols that have no value meaning (i.e., they’re purely types or uninstantiated namespaces) or are imported/exported with a type-only import/export somewhere earlier in the chain be imported with a type-only import so transpilers can know to drop those import specifiers. Obviously, auto-imports had to be updated to account for this when importing types or already-type-only symbols. This PR includes the changes to make working under those settings manageable, though there are further experience enhancements I need to investigate. Here’s a non-exhaustive summary of what happens now:--importsNotUsedAsValues=error
, you won’t see any type-only auto-imports. You’ll only get a type-only auto-import if it is needed to prevent an error or if it can use an existing type-only import declaration as opposed to adding a new import declaration.import type { Foo }
overimport { type Foo }
.import type { SomeType }
→import { SomeValue, type SomeType }
)import type Foo, { Bar }
is not allowed).Future improvements to look into:
If you have enough specifiers in
import type { A, B, C, D, ... }
, it is probably undesirable to convert that to a regular import upon adding a value import to it, since it would result in an explosion oftype
prefixes. At some point, you probably just want to add a new import statement. On the other hand, if each specifier is on its own line, it might not be bad to add all the prefixes and keep them combined, so this scenario needs some thought in order for us to guess the best thing to do.There’s still no support for promoting a type-only import to a regular import by attempting to use a value that you’ve already imported as type-only in an emitting position, e.g.
I used to think this was kind of sketchy, but now that auto-imports has to be willing to make a lot more guesses and be willing to put things in type-only imports more often, I’m coming around to the thought that the best thing we can do is just try to be as flexible as possible and fluidly rewrite your import format to match your usage as you go. (Existing
import type
prevents autocompletion of value import for TypeScript #44804 is related.)Other follow-up work