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

Unioned type for function param emits object instead of inline type for type that is based on a typedef #720

Closed
techfg opened this issue Nov 23, 2024 · 10 comments
Labels
bug Issue raised as a bug. fixed Fix implemented in latest version.

Comments

@techfg
Copy link

techfg commented Nov 23, 2024

What package is the bug related to?

typedoc-plugin-markdown

Describe the issue

When a function parameter accepts a union type which contains a type that is based on a typedef, the type that was created via typedef emits as object instead of the inline type.

Repro: https://stackblitz.com/edit/vitejs-vite-gkbey1

Steps to Reproduce

  1. Open repro
  2. npm run docs:md
  3. View files in docs-md/functions

Actual Result
Generated markdown for function handleFoo which accepts the union Foo | null contains object for the type of Foo

• **a**: `null` \| `object`

Additional Information

  1. The issue does not occur when generating html files (npm run docs:html)
  2. The issue does not occur in the following situations:
    1. handleFooOnly - Does not contain a union, param a is type Foo
    2. handleFoo2 - Defines a union type FooExplicit separately and uses it for the type parameter for a instead of the inline union
    3. handleFooExplicit - Uses a union type inline but does not use typedef

TypeDoc configuration

typedoc: 0.26.11
typedoc-plugin-markdown: 4.2.10
typescript" 5.6.3

Expected behavior

The type Foo should be generated inline similar to the way handleFooOnly which does not have a union type emits.

• **a**
• **a.a**: `string` = `''`
• **a.b**: `string` = `''`
@techfg techfg added the bug Issue raised as a bug. label Nov 23, 2024
@tgreyuk
Copy link
Member

tgreyuk commented Nov 27, 2024

Thanks for detailed description.

Fix in [email protected]

It was a bit tricky to format this in a decent way but currently is produces this output.

Screenshot 2024-11-27 at 18 36 35

https://github.com/typedoc2md/typedoc-plugin-markdown-scratchpad/blob/main/issues/720/docs/md/functions/handleFoo.md

Please note output for parameter listings has changed a bit for readability.

@tgreyuk tgreyuk added the fixed Fix implemented in latest version. label Nov 27, 2024
@techfg
Copy link
Author

techfg commented Nov 27, 2024

Hi @tgreyuk -

Thanks for the quick response on this, greatly appreciated!

Understood that the formatting gets complicated in this scenario, however I think the current in 4.3.0 is missing a key part of the type by not having a | between the types.

Repro: https://stackblitz.com/edit/vitejs-vite-8b5crt?file=src%2Findex.ts

TypeDoc configuration
typedoc: 0.27.0
typedoc-plugin-markdown: 4.3.0
typescript" 5.7.2

In the case of handleFooExplicit, the generated result is:
image

However, in the case of handleFoo, the generated result is:
image

Even thought the types are defined in an identical way with the only difference being their "upstream" definitions:

export const handleFoo = (a: Foo | null) => {};
export const handleFooExplicit = (a: FooExplicit | null) => {};

In the HTML version, the result is:
image

Do you think it makes more sense and would it be possible to delimit null and {a: string;b: string; } with a | and just put on the same line or at least add a | to the end of each line (except the last)?

@tgreyuk
Copy link
Member

tgreyuk commented Nov 27, 2024

Yes makes sense. I assume example 1 is preferable to example 2?

Example 1:
Screenshot 2024-11-27 at 22 39 30

Example 2:
Screenshot 2024-11-27 at 22 39 56

@techfg
Copy link
Author

techfg commented Nov 28, 2024

Thanks @tgreyuk. Yeah, my preference would be Example 1 as it mirrors what the output is in the FooExplicit scenario and also the HTML equivalent.

A few additional notes:

  1. I realized that the typedoc 0.27.0 repro from my last message wasn't saved so I've updated it to ensure the lastest typedoc, typedoc-plugin-markdown & typescript are referenced in package.json
  2. Another scenario where this same formatting issue arises is in the following - I've added handleFooInline to cover this so that you have a repro
export const handleFooInline = (a: { a: string; b: string } | null) => {};
  1. Beyond the | formatting, the current output emits a.a and a.b which differs from the generated HTML for the same function which does not include the additional definition of a since it's already inlined. I'm not sure why the extra definition is emitted so possibly there is a good reason it behaves the way it does. That said, it does differ from what the HTML equivalent generates and in the case where there are multiple complex types in the union, things could get rather confusing I fear. For example, the following:
export const handleFooInlineMulti = (
  a: { a: string; b: string } | { x: string; y: string } | null
) => {};

Generates the following MD which has two issues:

  1. It does not include {'x': 'string';'y': 'string'; } in the definition of a itself (yellow highlight)
  2. It includes additional definition of each complex type of a but since they are already documented for a itself this results in duplicates (red highlight):
    image

While the HTML equivalent generates:
image

I believe the {x: string, y:string} should be emitted for a itself here and possibly the additional definition a.a, a.b, a.x & a.y isn't needed in this scenario?

@tgreyuk
Copy link
Member

tgreyuk commented Nov 28, 2024

@techfg thanks for the comments - this kind of detailed feedback is invaluable and greatly appreciated.

Another scenario where this same formatting issue arises is in the following - I've added handleFooInline to cover this so that you have a repro

Will review thank you.

Beyond the | formatting, the current output emits a.a and a.b which differs from the generated HTML for the same function which does not include the additional definition of a since it's already inlined.

You are correct, the html theme does not include further inlined declarations unless there are associated doc comments, in which case it does render the detailed declaration.

Screenshot 2024-11-28 at 13 22 29

This is a pattern i have considered implementing too but i found it more deterministic just retain the same behaviour regardless if comments are present. However on reflection there is obviously a case not to render this extended view if there is nothing useful to show (ie associated comments), and aligning with the html theme in this regard is probably the way to go.

That said, it does differ from what the HTML equivalent generates and in the case where there are multiple complex types in the union, things could get rather confusing I fear. For example, the following:

Yes i thought about this too which is partly why the initial implementation was in blocks, however i think it can be implemented in a way that works, and if we are not displaying inline details all the time it becomes less of an issue.

@techfg
Copy link
Author

techfg commented Nov 28, 2024

Happy to try to help @tgreyuk, glad your finding the feedback useful :)

Makes sense about where you initially took the approach to always emit vs. only when comments are present. I do think that trying to mirror the HTML equivalent as much as possible may be the best course but understood if that presents challenges and I don't think it's worth bending over backwards to try to make that happen if its not straightforward enough.

Just want to make sure you saw the comment about the issue where in the following, { x: string; y: string } is not emitted for a (yellow highlighted area):

export const handleFooInlineMulti = (
  a: { a: string; b: string } | { x: string; y: string } | null
) => {};

Thank you!

@tgreyuk
Copy link
Member

tgreyuk commented Dec 1, 2024

As discussed - fixes in [email protected]

Screenshot 2024-12-01 at 23 09 40 Screenshot 2024-12-01 at 23 09 53

@techfg
Copy link
Author

techfg commented Dec 2, 2024

Looking good in 4.3.1, thank you @tgreyuk!

Only feedback I'd offer is that there is a space between certain areas (green arrows) and no space between other areas (red arrows). For consistency, possibly add a space where the red arrows are?

image

@tgreyuk
Copy link
Member

tgreyuk commented Dec 8, 2024

spacing updated in [email protected]

@techfg
Copy link
Author

techfg commented Dec 8, 2024

Looks great, thanks for the quick response @tgreyuk!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue raised as a bug. fixed Fix implemented in latest version.
Projects
None yet
Development

No branches or pull requests

2 participants