-
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
JSDoc equivalent of import * #41825
Comments
cc @sandersn for visibility |
Ran into a similar related issue today I attempted to do the following /** @typedef {import('../../types.js')} T */
/**
* @return {Promise<T.Result<any>>}
*/
module.exports = async (args) => { ... } Where
And then I got
I wanted to treat the entire package as a namespace so that I can import it and reference types inside of it using the |
Due to random dumb luck and just trying stuff I discovered that you can You may be able to declare that various types exists in You can also use namespaces to This does not solve any of the importing use cases, however it turns out that the author whom writes the exports can export into a global namespace which can be used anywhere without |
Poor mans solution I've settled on is along these lines: lib.js (implementation lives here)import * as API from "./result.js"
/**
* @template T
* @param {T} value
* @returns {API.Result<never, T>}
*/
export ok = (value) => ({ ok: true, value }) result.js (just a facade for lib.js)export * from "./lib.js" result.ts (shadow .js to add types)export * from "./lib.js"
export type Result<X, T> =
| { ok: true, value: T }
| { ok: false, error: X } Now any other module could do following: import * as Result form "../path/to/result.js"
/**
* @template X, T
* @param {Result.Result<X, T>} result
* @param {(t:T) => U} f
* @returns {Result.Result<X, U>}
*/
export const map = (result, f) =>
result.ok ? Result.ok(f(result.value)) : result |
Just to clarify what the issue actually is, essentially this: /**
* @typedef {import("./someModule.js")} SomeModule
*/ is actually equivalent to this: /**
* @typedef {typeof import("./someModule.js")} SomeModule
*/ In TypeScript however the following are distinct in general: import type * as SomeModule from "./someModule.js";
type SomeModule = typeof import("./someModule.js"); |
Hey Team, Any updates on this I keep introducing facade files just to workaround retyping all the generics at every import, but it really feels like there needs to be a proper solution. I also came across #22160 which seems to be asking fro the same feature with different syntax. |
Not sure is it related but it seem the This affect constructor that I can't see the signature and autocomplete on the constructor |
@RyanCavanaugh @sandersn any updates on this ? This is probably the most annoying limitation when using TS with JSDoc. If someone is willing to mentor me on this, I’d be up to put my time into this. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
We decided to accept this issue. Here's an outline of my thoughts for anybody that wants to try implementing this:
That's very high level. I likely skimmed over lots of work in saying that the compiler needs to provide the same semantics as |
@sandersn I'll buy you a sandwich when this lands |
Hope it will handle such cases with generics. Or maybe you know another way to handle it without importing type right in the // values-of.type.js
/**
* @template T
* @typedef { T[keyof T] } ValuesOf
*/ // settings-button-payload.type.js
// error ValuesOf is a generic
/** @typedef {import('../types/types.js').ValuesOf} ValuesOf */
/** @typedef {typeof import('../enums/enums.js').SettingButtonLabel} SettingButtonLabel */
/**
* @typedef {{
* isDefaultChecked: boolean
* label: ValuesOf<SettingButtonLabel>
* }} SettingsButtonPayload
*/ |
I just found a way to fix it by reading the 'The Saga of the Closure Compiler, and Why TypeScript Won' article. The method is quite specific. 🤯 // values-of.type.js
/**
* @template T
* @typedef {T[keyof T]}
*/
let ValuesOf
export { ValuesOf } // settings-button-payload.type.js
import { ValuesOf } from '~/libs/types/types.js'
/** @typedef {typeof import('../enums/enums.js').SettingButtonLabel} SettingButtonLabel */
/**
* @typedef {{
* isDefaultChecked: boolean
* label: ValuesOf<SettingButtonLabel>
* }} SettingsButtonPayload
*/ |
I addition to Within unifiedjs we use a lot of re-exports to expose the public interface including types. An example is https://github.com/mdx-js/mdx/blob/3.0.1/packages/mdx/index.js. This code is equivalent to: export type Fragment = import('./lib/util/resolve-evaluate-options.js').Fragment
// etc In TypeScript you would write this as: export { Fragment } from './lib/util/resolve-evaluate-options.js'
// etc This results in a loss of descriptions of those types for the users. Plus generics need to be redefined. |
Search Terms
Suggestion
Provide a JSDoc equivalent of
import * as Sub from "./sub"
so that types & interfaces from the./sub
module could be referenced asSub.Type
,Sub.Interface
.I have no preference in terms of actual syntax, but in my experience general expectation had been that following syntax should do just that (but it is not and I can't seem to figure out what does
Sub
results in here:If above is not a viable options maybe using same
*
character could be an options:Or maybe whole new
@import
jsdoc tag.Use Cases
js-ipfs (fairly large code base) has adopted TS via JSDoc syntax but dealing with large number of imported types & interfaces from other modules had been a major source of pain for following reasons:
@typedef {import('...').Name} Alias
.@template
tagsany
All of the above make otherwise mostly good experience to be painful.
Current approach also has side effect of turning imported interfaces into types (see #41258) which than can't be used in
implements
syntax as they are no longer interfaces.Given that it is possible to do
import * as Sub from "./sub"
to get a namespace of exports in TS syntax it seems like equivalent in jsdoc syntax would:@typedef {import(...).Name} Name
declarations.@temaplate
tags.Examples
Consider following TS code:
Same code with JSDoc syntax turns into following:
Note: Above code won't even produce desired typedefs due to #41258
And now if we had what this issue proposes it would be:
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: