-
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 Typedef Syntax for Overloadable Constructors #55916
Comments
If you want a generic constructor, you can write /**
* @template T
*/
class C {
/**
* @template T
* @overload
* @param {T} value
* @return {C<T>}
*/
/**
* @template T
* @overload
* @param {T} first
* @param {T} second
* @return {C<T>}
*/
/**
* @param {T} first
* @param {T} [second]
*/
constructor(first, second) {
}
}
const x = new C(123);
// ^?
const y = new C("hello", "world");
// ^?
const y = new C(123, "hello");
// ^? It is questionable whether that's the right way to declare /**
* @template T
*/
class C {
/**
* @overload
* @param {T} value
*/
/**
* @overload
* @param {T} first
* @param {T} second
*/
/**
* @param {T} first
* @param {T} [second]
*/
constructor(first, second) {
}
}
const x = new C(123);
// ~~~
// Argument of type 'number' is not assignable to parameter of type 'T'.
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'number'.
const y = new C("hello", "world");
// ~~~~~~~
// Argument of type 'string' is not assignable to parameter of type 'T'.
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'. |
Looking more closely at your code, I realize you're asking about something else. You can just express /** @typedef {keyof DocumentEventMap} EventType */
/** @template {EventType} T @typedef {DocumentEventMap[T]} ObserverEvent */
/** @template {EventType} T @typedef {(event: ObserverEvent<T>) => unknown} ObserverEventListener */
/**
* @typedef {Object} BaseObserver
*/
/**
* @typedef {{
* new <T extends EventType>(type: T, listener: ObserverEventListener<T>): BaseObserver;
* new <T extends ReadonlyArray<EventType>>(types: T, listener: ObserverEventListener<T[number]>): BaseObserver;
* }} BaseObserverConstructor
*/ |
@DanielRosenwasser The example that you gave me seems to fail when the various Additionally, the comments for the I actually prefer the first example you showed me, where I can simply use |
It seems like this is a bug with overloads, potentially. Will open a separate issue in that case. |
Yeah, in TS itself, construct signatures can't add more generic type parameters than their containing class. In the JSDoc version, it's an irregularity that overload signatures permit them. The doc comments being lost is a valid bug as well if you'd like to file something there. |
…rver` This allows us to have our documentation and our types in the same place! Hopefully it'll make developer experience better in the long run. We'll make this update for the `FormValidityObserver` as well. HUGE thanks to @DanielRosenwasser! (See his current solution for JSDocs in microsoft/TypeScript#55916.) This is GAME CHANGING.
🔍 Search Terms
constructor jsdoc overload
✅ Viability Checklist
⭐ Suggestion
Currently, with pure TypeScript, it's possible to create an overloaded, generic constructor type. (The benefits of overloaded generic constructors are better detailed in #40451.) However, there is no similar concept available in JSDocs. After migrating a TS project to JSDocs, I found this to be a hindrance. (There are some workarounds, but they still negatively impact user experience surrounding
import
s.)It would be great if this use case was supported in JSDocs land. Alternatively, if #40451 was resolved, I'm assuming that this issue would be inherently be resolved as well. Rich Harris made a compelling case for using JSDocs in his interview with the Primeagen and his interview with Kev from Svelte Society. It seems there are more library authors interested in reaching for JSDocs (through TS) for simplicity (myself included); so greater support in situations like these would be fantastic.
📃 Motivating Example
I'm appealing to #40451 and the example in #52585 here. If I want to create a DOM-watcher class in TypeScript that will have a consistent, unchanging interface and that can be constructed in different ways, I need a generic constructor:
This works fine in TS, but it's incompatible with JSDocs -- causing friction during migration. If JSDoc support was added, perhaps we'd probably have something like the following:
That said, this can also be solved by resolving #40451. Resolving said issue would remove the need for any additional TS-specific JSDoc syntax. However, if that is not up for consideration, then a JSDoc syntax that mimics TypeScript's behavior would be very helpful.
💻 Use Cases
1) What do you want to use this for?
The example above is probably the clearest example of what I need this for. This is for a project that I'm actively working on.
2) What shortcomings exist with current approaches?
The current shortcoming is that this isn't possible for those only wanting to use JSDocs. This creates some minor friction in how a project structures its
exports
(inpackage.json
) and how a project structures its filesystem. (I didn't require extra.d.ts
files before migrating to JSDocs.) It also separates a class method's documentation (defined in aninterface
in a.d.ts
file) from its implementation (defined in ajs
file) -- resulting in lesser maintainability.3) What workarounds are you using in the meantime?
The current workaround is to create a separate
<FILE_NAME>Types.d.ts
file that has the TS Generic Constructor defined. The constructor can be imported from the types file by the JS file. This would need to be done for every JavaScript file. Alternatively, a global types file for the application/library being built can be created, and the types would be imported collectively from there instead.This does add some complexity for library maintainers using
package.json
'sexports
property, however.The text was updated successfully, but these errors were encountered: