Uh oh!
There was an error while loading. Please reload this page.
feat(41825): JSDoc equivalent of import * - #57207
Conversation
TypeScript Bot (typescript-bot)
commented
Jan 28, 2024
Looks like you're introducing a change to the public API surface area. If this includes breaking changes, please document them on our wiki's API Breaking Changes page. Also, please make sure Daniel Rosenwasser (@DanielRosenwasser) and Ryan Cavanaugh (@RyanCavanaugh) are aware of the changes, just as a heads up. |
Uh oh!
There was an error while loading. Please reload this page.
db6bd73 to
0b0029dCompareTypeScript Bot (@typescript-bot) pack this |
Heya Daniel Rosenwasser (@DanielRosenwasser), I've started to run the tarball bundle task on this PR at 0a20ad3. You can monitor the build here. |
Hey Daniel Rosenwasser (@DanielRosenwasser), I've packed this into an installable tgz. You can install it for testing by referencing it in your and then running There is also a playground for this build and an npm module you can use via |
Something we should test /** * @importType * as Foo from "foo" */and /** * @importType { * A, * B, * C, * } from "foo" */ |
In our design meeting, I brought up some of the discussion on Twitter around the tag name. I think the team is up for just calling it Something that came up was the use of /** * @import { type Foo } from "foo" */The preference was to disallow them for now, even though it might make copy/pasting from TS to JS easier. The idea was can always relax that restriction. Another two things that I do want us to test:
As raised above, multi-line should just work: /** * @import { * A, * B, * C, * } from "foo" */However, I don't know exactly how this should be handled, and I am curious to hear thoughts from Nathan Shively-Sanders (@sandersn) (who can also help out with where the leading /** * @import * as Foo from "foo" ^ what is this? */As I write this up, it really makes me realize like the devil is in the details. 😅 |
/** * @import { * A, * B, * C, * } from "foo" */Daniel Rosenwasser (@DanielRosenwasser) I think the TypeScript/src/compiler/scanner.ts Line 1062 in 821b1d8 TypeScript/src/compiler/scanner.ts Lines 1922 to 1926 in 821b1d8 |
Oleksandr Tarasiuk (a-tarasyuk)
commented
Feb 2, 2024
Daniel Rosenwasser (@DanielRosenwasser) The existing auto-import logic will add // @Filename: /a.tsexportdefaultinterfaceA{}// @Filename: /test.js/** * @param { A/**/}a*/exportfunctionf(a){} |
/** * @import * as Foo from "foo" ^ what is this? */Daniel Rosenwasser (@DanielRosenwasser) It's a tricky case because the first /** * @import * * as Foo from "foo" */ |
I would say so - however, in the interest of keeping this PR smaller, you might want to do a follow-up PR instead. Andrew Branch (@andrewbranch) might have thoughts here. Regarding the ambiguity with |
Oleksandr Tarasiuk (a-tarasyuk)
commented
Feb 7, 2024
Daniel Rosenwasser (@DanielRosenwasser) These imports are currently transformed into |
Since these have type-only import semantics in JSDoc, I would have assumed they would translate to type-only import declarations in the .d.ts file. I’m not sure it actually matters though. We have to remember that JS-based declaration emit works completely differently from TS-based declaration emit—instead of walking the source file, it walks the symbol table and just synthesizes types for stuff. So as far as the declaration emitter is concerned, this feature really changes nothing. It’s just one more way to give visible symbols a type, but the declaration emitter already doesn’t know or care how anything got its type when working from JS. |
Nathan Shively-Sanders (sandersn)
left a comment
There was a problem hiding this comment.
Not done reviewing, but I found that I wrote some requests for tests last time I looked at this and forgot to post them.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Nathan Shively-Sanders (sandersn)
commented
Feb 7, 2024
I'm also OK with any decision, and I think strict no-newline one is a good place to start except that it would require special-casing consttagName=parseJSDocIdentifierName(/*message*/undefined);constindentText=skipWhitespaceOrAsterisk();So I'd personally leave it as interpreting a leading asterisk as decoration: /** * @import * { foo, bar } * from "multiline.js" */equivalent to /** * @import * * as multiline from 'multiline.js' */works. |
Wesley Wigham (weswigham)
left a comment
There was a problem hiding this comment.
I think this is fine? Andrew Branch (@andrewbranch) should give the type-only behavior a once-over, though.
Andrew Branch (andrewbranch)
commented
Mar 26, 2024
I was skimming for a test like this and I didn’t see one, so let me know if I missed it: // @declaration: true// @emitDeclarationOnly: true// @checkJs: true// @allowJs: true// @filename: 0.tsexportdefaultinterfaceFoo{}exportinterfaceI{}// @filename: 1.js/** @import Foo, { I } from './0' *//** * @param {Foo} a * @param {I} b */exportfunctionfoo(a,b){}Is this input syntax valid, and does it emit valid declaration file syntax? The input syntax should be valid in my opinion, but if it wasn’t handled specifically, it may emit invalid syntax on the output: importtypeFoo,{I}from'./0';// ^^^^^^^^^^^^^^^// A type-only import can specify a default import or named bindings, but not both.(1363) |
Bret Comnes (bcomnes)
commented
Jun 4, 2024
I love this feature! I've noticed though, that if you import a type with the new syntax, and then only use that type inside of another typedef (used or unused in the js file), you get a ts6133 "is declared but its value is never read." warning, despite the imported type resolving and the new typedef being declared properly. It only counts read state when something is assigned the type directly. |
Andrew Branch (andrewbranch)
commented
Jun 5, 2024
Bret Comnes (@bcomnes) I can't reproduce that behavior; here's my attempt in the playground: https://www.typescriptlang.org/play/?noUnusedLocals=true&ts=5.6.0-dev.20240605&filetype=js#code/PTAEAEDsHsFVIK4GcCmATAMtAxgQwDZIBcoALgE4IoCwAUHQJYC2ADtOaaAEQBmSXAbjp1gAKlERmbDqADeoAOrkGpFADEG+FAHkWpBtEhJQAX1A9y0Jtz5dQo4MNohQ8bFaYpI+yAHNzDAAeKMakABYooCjkluQiYGIS4KQAnizoKDxySirqmjp6BkZmCmra9sBAA If you can show an example, could you open a new issue? Thanks! |
Hrmmm you are right. I'm having a hard time coming up with a minimal reproducible example. I think it may be related to cycles in the type import, but also related to usage of the cycling type. I'll report back if I can pin it down. |
Guillaume Humbert (acidoxee)
commented
Jun 21, 2024
My apologies if this has already been discussed, but it seems the new For additional details, my codebase is mostly ESM, but some parts still have to be CJS for compatibility reasons with "old" tools. In those CJS parts, I previously imported types from the ESM part like this: /** @typedef {import('../path/to/some/ESModule.js', { with: { 'resolution-mode': 'import' } }).MyType} MyType */I have tried migrating to the new /** @import {MyType} from '../path/to/some/ESModule.js' with { 'resolution-mode': 'import' } */Using the above syntax yields this error message:
Am I wrong, or is this simply not available yet for |
Oleksandr Tarasiuk (a-tarasyuk)
commented
Jun 21, 2024
Guillaume Humbert (@acidoxee) Can you create a new issue? I'll take a look at it. |
Guillaume Humbert (acidoxee)
commented
Jun 21, 2024
Sure Oleksandr Tarasiuk (@a-tarasyuk), here you go! #58955 |
Andrew Branch (@andrewbranch) maybe i can reproduce this with my case: Version: 1.91.0-insider types.d.ts exporttypeTestType={route: string;method?: string|undefined;handle: Function;upload?: boolean|undefined;option?: Object|undefined;};test1.js /** @import { TestType } from './types.d.ts' */exportdefaultasyncfunctiondoSomething(){/** @type {TestType[]} */consttypes=[];returntypes;}test2.js /** @import { TestType } from './types.d.ts' */exportdefault{/** @type {TestType[]} */types: []};update2: |
DanoR (zheung)
commented
Jun 23, 2024
For the same project as above, I found another problem: tsc doesn't seem to recognize types imported via Import (A place for python bower components) (@import) correctly. |
Jimmy Beaudoin (jbeaudoin11)
commented
Jul 3, 2024
Hi guys, not sure if i should simply open an issue instead of writing here but is it me or it's not possible to just import all ? |
In general it's not best practice to comment on a closed PR or issue since people stop following as often, and creates noise in the conversation. To answer your question, you have to create a name for the import: /** @import * as myTypes from "./types.ts" */// ^^^^^^^^^^JavaScript/TypeScript doesn't support an "import all the things from this module into the current scope" sort of import statement. |
Jimmy Beaudoin (jbeaudoin11)
commented
Jul 3, 2024
Alright, i'm really confused, i swear i used to do this all the time before ESM was a thing but maybe i'm wrong... |
jbeaudoin-lf
commented
Jan 14, 2025
juhort You are trying to import from a ts file ? "./better-omit.ts" ? Just use the native typescript syntax like you're importing a module or types. This feature is only useful if you do hybrid ts in js via jsdoc. |
juhort Just use ts import in a ts file even if you're only using it in the tsdoc. The goal of this feature is to improve the DX around jsdoc types in js files ( |
Bret Comnes (bcomnes)
commented
Jan 14, 2025
I have seen some oddness with node native esm, when you Import (A place for python bower components) (@import) a .d.ts it actually expects a .js extension, even if there is no associated .js with that declaration file. The use case being: you want to define some types in real ts syntax but then import it into a .js file. |





Fixes#22160
Fixes#41825
Fixes#41825 (comment)