-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
feat(41825): JSDoc equivalent of import * #57207
Conversation
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 @DanielRosenwasser and @RyanCavanaugh are aware of the changes, just as a heads up. |
db6bd73
to
0b0029d
Compare
@typescript-bot pack this |
Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 0a20ad3. You can monitor the build here. |
Hey @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 @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"
*/ @DanielRosenwasser I think the TypeScript/src/compiler/scanner.ts Line 1062 in 821b1d8
TypeScript/src/compiler/scanner.ts Lines 1922 to 1926 in 821b1d8
|
@DanielRosenwasser The existing auto-import logic will add // @Filename: /a.ts
export default interface A { }
// @Filename: /test.js
/**
* @param { A/**/ } a
*/
export function f(a) { } |
/**
* @import
* as Foo from "foo"
^
what is this?
*/ @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. @andrewbranch might have thoughts here. Regarding the ambiguity with |
@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. |
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.
Not done reviewing, but I found that I wrote some requests for tests last time I looked at this and forgot to post them.
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 const tagName = parseJSDocIdentifierName(/*message*/ undefined);
const indentText = 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. |
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 think this is fine? @andrewbranch should give the type-only behavior a once-over, though.
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.ts
export default interface Foo {}
export interface I {}
// @filename: 1.js
/** @import Foo, { I } from './0' */
/**
* @param {Foo} a
* @param {I} b
*/
export function foo(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: import type Foo, { I } from './0';
// ^^^^^^^^^^^^^^^
// A type-only import can specify a default import or named bindings, but not both.(1363) |
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. |
@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. |
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 |
@acidoxee Can you create a new issue? I'll take a look at it. |
Sure @a-tarasyuk, here you go! #58955 |
@andrewbranch maybe i can reproduce this with my case: Version: 1.91.0-insider types.d.ts export type TestType = {
route: string;
method?: string | undefined;
handle: Function;
upload?: boolean | undefined;
option?: Object | undefined;
}; test1.js /** @import { TestType } from './types.d.ts' */
export default async function doSomething() {
/** @type {TestType[]} */
const types = [];
return types;
} test2.js /** @import { TestType } from './types.d.ts' */
export default {
/** @type {TestType[]} */
types: []
}; update2: |
For the same project as above, I found another problem: tsc doesn't seem to recognize types imported via @import correctly. |
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. |
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... |
Fixes #22160
Fixes #41825
Fixes #41825 (comment)