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 files built from JSDoc typedefs with optional parameters reference indirect dependency #48242

Closed
Methuselah96 opened this issue Mar 14, 2022 · 7 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@Methuselah96
Copy link

Bug Report

πŸ”Ž Search Terms

jsdoc
declaration files
optional parameters
.d.ts
grandchild
indirect dependency

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about ???

⏯ Playground Link

Can't provide TypeScript playground because I don't see an option to build JSDoc types. But I did create a contained repo.

πŸ’» Code

child/index.js:

/**
 * @typedef {import('grandchild').Options} Options
 */

parent/index.js:

/**
 * @typedef PluginOptions
 * @property {import('child').Options} [childOptions]
 */

πŸ™ Actual behavior

parent/index.js compiles to:

export type PluginOptions = {
    childOptions?: import("grandchild").Options | undefined;
};

This causes problem because parent doesn't have a direct dependency on grandchild

πŸ™‚ Expected behavior

parent/index.js compiles to:

export type PluginOptions = {
    childOptions?: import("child").Options | undefined;
};

Note that this works correctly if childOptions is not optional. As in, this:

/**
 * @typedef PluginOptions
 * @property {import('child').Options} childOptions
 */

Correctly compiles to:

export type PluginOptions = {
    childOptions: import('child').Options;
};
@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Mar 14, 2022
@RyanCavanaugh
Copy link
Member

Declaration emit has the following heuristics:

  • If you can use the input text as-is, do (this does not apply here because | undefined needs to be added)
  • Otherwise, use the "best" identifier for the type
    • An originating declaration is considered better than a re-export

So you should be able to get the desired emit by writing

/**
 * @typedef PluginOptions
 * @property {import('child').Options | undefined} [childOptions]
 */

Otherwise this is an expected property of the declaration emitter

@Methuselah96
Copy link
Author

Methuselah96 commented Mar 14, 2022

  • If you can use the input text as-is, do (this does not apply here because | undefined needs to be added)

Why is | undefined added? Is there a way to make it not add that?

@Methuselah96
Copy link
Author

  • Otherwise, use the "best" identifier for the type
    • An originating declaration is considered better than a re-export

Why is the originating declaration considered better than a re-export in this case? It seems inherently problematic to use the originating declaration if the originating declaration is importing it from another package.

@RyanCavanaugh
Copy link
Member

| undefined is added for conformance with exactOptionalPropertyTypes

The originating declaration is considered better since it's more likely to have a meaningful name, is less likely to move around, requires fewer hops when navigating the code, etc..

Erasing an upstream dependency by re-exporting all of its symbols isn't a scenario for the declaration emitter (not that it would have that function here anyway).

@Methuselah96
Copy link
Author

I'm not expecting the declaration emitter to re-export any symbols, I'm expecting it recognize that it can't reuse the underlying type if the underlying type uses an import since it might not have access to that dependency.

@Methuselah96
Copy link
Author

Methuselah96 commented Mar 15, 2022

In this case it's invalid to use the originating declaration because it's trying to import a package that it doesn't have a dependency on. Why is that considered "not a defect" of the current heuristics?

Methuselah96 added a commit to Methuselah96/react-markdown that referenced this issue Mar 30, 2022
This is required for TypeScript to avoid referencing the wrong type (see microsoft/TypeScript#48242 (comment)).
wooorm pushed a commit to remarkjs/react-markdown that referenced this issue Mar 31, 2022
@github-actions
Copy link

github-actions bot commented Jun 8, 2023

This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

2 participants