Skip to content
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

Declaration merging in plain JS with JSDoc #57559

Open
6 tasks done
trusktr opened this issue Feb 27, 2024 · 7 comments
Open
6 tasks done

Declaration merging in plain JS with JSDoc #57559

trusktr opened this issue Feb 27, 2024 · 7 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@trusktr
Copy link
Contributor

trusktr commented Feb 27, 2024

πŸ” Search Terms

jsdoc declaration merging

βœ… Viability Checklist

⭐ Suggestion

Ability to merge declarations.

πŸ“ƒ Motivating Example

For example, this is a declaration merge in TS:

export const Foo = makeFooClass()
export type Foo = InstanceType<typeof Foo>

In JS we can't do this. I was hoping for something similar to this to achieve the same:

export const Foo = makeFooClass() // returns a class
/** @export {InstanceType<typeof Foo>} Foo */

πŸ’» Use Cases

  1. What do you want to use this for? To merge declarations in certain cases.
  2. What shortcomings exist with current approaches? There's no way to do it AFAICT
  3. What workarounds are you using in the meantime? None
@fatcerberus
Copy link

I don’t think that counts as a declaration merge, it’s just β€œdeclaring a type and a value with the same name”. There’s no requirement that the two Foos be related as they exist in separate namespaces within the compiler. Declaration merge is when e.g. you declare an interface more than once and the second one augments the first.

@trusktr
Copy link
Contributor Author

trusktr commented Feb 27, 2024

Maybe its named something else. If so, what is this pattern named where a single identifier carries both a type and a value? I could not find anything about it in the TS docs (maybe I don't know what to search for).

From my perspective, I thought it was one (of multiple) forms of "declaration merging" because two things are being merged: a variable declaration, and a type declaration. I however did not see this on the Declaration Merging page in the docs.

@trusktr
Copy link
Contributor Author

trusktr commented Feb 27, 2024

Maybe the syntax needs to be

/**
 * @export
 * @typedef {InstanceType<typeof Foo>} Foo
 */

@trusktr
Copy link
Contributor Author

trusktr commented Feb 27, 2024

Ah, @Gerrit0 pointed out that the following works because typedef is automatically exported:

export const Foo = makeFooClass() // returns a class
/** @typedef {InstanceType<typeof Foo>} Foo */

@trusktr
Copy link
Contributor Author

trusktr commented Feb 27, 2024

I do not see that this type exports feature is mentioned here:

https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html

Perhaps we need to add more info to that page.

@fatcerberus
Copy link

If so, what is this pattern named where a single identifier carries both a type and a value? I could not find anything about it in the TS docs

I don't think there's a name for it because it's just declaring two different things that happen to have the same name, but the compiler considers them separate entities as one exists in type-space and the other in value-space1. Nothing is really being merged.

Footnotes

  1. This split between type-space and value-space is why the typeof operator exists. There's no requirement that Foo and typeof Foo be related, it's just in practice they usually are. ↩

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Feb 29, 2024
@trusktr
Copy link
Contributor Author

trusktr commented Sep 10, 2024

one exists in type-space and the other in value-space1. Nothing is really being merged.

They're being "merged" in the sense that the end user who will import the type can reference it with a single identifier, and to them it is the "one and same thing".

import {Foo} from './Foo.js'

const f = new Foo() // uses *both* Foos, which to the user is a single thing.

Maybe it can be called type value merging or something, but it definitely is some type of a merge (yeah, not merging of two interfaces)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants