Open natalieethell opened 5 years ago
I'm curious in general about how documentation systems represent merged declarations, which seem to be a TypeScript-specific requirement.
Consider a definition like ApiReleaseTagMixin:
Currently DocFX groups API items under headings by type (e.g. "Classes", "Interfaces", "Enums", and "Functions" in this example). Today ApiReleaseTagMixin
will get three declarations that appear under "Interfaces", "Functions", and "Namespaces", and each of these entries would have its own documentation.
Using the TSDoc tags @natalieethell proposed above, we could maybe improve that:
/**
* The mixin base class for declarations that have an associated release tag.
*
* @remarks
* The interface describes the non-static members of the mixin class.
* The namespace contains the static members.
*
* {@documentAs mixin}
*/
interface ApiReleaseTagMixin {
}
/** {@partOf (ApiReleaseTagMixin:interface)} */
namespace ApiReleaseTagMixin {
}
/**
* Constructs a mixin base class conforming to the {@link (ApiReleaseTagMixin:interface)}
* interface.
* @param baseClass - The base class to extend
* @returns a base class that implements `ApiReleaseTagMixin` and extends `baseClass`
*/
function ApiReleaseTagMixin<TBaseClass extends IApiItemConstructor>(baseClass: TBaseClass):
TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin) {
}
The @documentAs
tag would cause this to go under a custom heading "Mixins" instead of "Interfaces".
And @partOf
tag causes the namespace signature to be documented with the interface (rather than getting its own documentation entry), like this:
ApiReleaseTagMixin Mixin
The mixin base class for declarations that have an associated release tag.
Signature:
interface ApiReleaseTagMixin
namespace ApiReleaseTagMixin
Remarks
The interface describes the non-static members of the mixin class. The namespace contains the static members.
Whereas the function would get its own documentation entry under the "Functions" section as usual:
ApiReleaseTagMixin Function
Constructs a mixin base class conforming to the ApiReleaseTagMixin interface.
Signature:
function ApiReleaseTagMixin<TBaseClass extends IApiItemConstructor>(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin);
Parameters
. . .
@dend
We already established in https://github.com/Microsoft/tsdoc/issues/9 that function overloads should be documented separately. But Office Addin-ins encountered a bunch of function overloads that exist purely for technical reasons (due to two different enum representations in this case). For example:
/**
*
* Deletes the cells associated with the range.
*
* [Api set: ExcelApi 1.1]
*
* @param shift - Specifies which way to shift the cells. See Excel.DeleteShiftDirection for details.
*/
delete(shift: Excel.DeleteShiftDirection): void;
/**
*
* Deletes the cells associated with the range.
*
* [Api set: ExcelApi 1.1]
*
* @param shift - Specifies which way to shift the cells. See Excel.DeleteShiftDirection for details.
*/
delete(shift: "Up" | "Left"): void;
The @partOf
tag could help with that problem, by allowing the above pattern to be simplified to this:
/**
*
* Deletes the cells associated with the range.
*
* [Api set: ExcelApi 1.1]
*
* @param shift - Specifies which way to shift the cells. See Excel.DeleteShiftDirection for details.
*/
delete(shift: Excel.DeleteShiftDirection): void;
/** {@partOf (delete:1)} */
delete(shift: "Up" | "Left"): void;
@AlexJerabek @Zlatkovsky
How would this affect overloads with differently documented parameters? Here's a common example from our d.ts:
load(option?: Excel.Interfaces.StyleCollectionLoadOptions & Excel.Interfaces.CollectionLoadOptions): Excel.StyleCollection;
load(option?: string | string[]): Excel.StyleCollection;
load(option?: OfficeExtension.LoadOption): Excel.StyleCollection;
The documentation would refer to the "main" declaration (i.e. the one that doesn't have an @partOf
tag). If the other declarations had different parameters, they wouldn't get documented.
Am I correct in thinking @partOf
wouldn't help the Intellisense experience? Would the user see the partOf
text or the "main" function's description?
It depends. If @partOf
was considered important enough to be made part of the TSDoc core standard, then to the extent that Visual Studio Code supports TSDoc, the IntelliSense would work.
Just to be clear, individual parameters on overloads would not be explicitly documented with @param
tags, correct? We'd have to fully contain all that data in the base function's description. That's all reasonable, though there might be cases with particular restrictions for the overloaded parameters (@ElizabethSamuel-MSFT might have such scenarios in Outlook).
Please let us know when this is functionality is supported in the web-build-tools suite.
Update: PR https://github.com/microsoft/rushstack/pull/1646 adds most of the machinery needed to implement a @partOf
tag.
Would this work for merging interface docs into class docs? Using the example from https://github.com/microsoft/rushstack/issues/1921:
/**
* @public
*/
export class MyWidget extends EventEmitter {
// class implementation goes here
}
/**
* {@partOf (MyWidget:class)}
*/
export interface MyWidget {
// `on()` and `once()` declarations for MyWidget events
}
Would this work for merging
interface
docs intoclass
docs?
When designing @partOf
, we did not think very much about how to handle API items that contain other nested items. Consider this example:
/**
* {@partof (Example:namespace)}
*/
interface Example {
a: number;
/** Description 1 */
b: number
}
namespace Example {
/** Description 2 */
export const b: string = 'b';
export const c: string = 'c';
}
What does the table of contents show? Should the items be mixed together like:
A different strategy would be to keep them as separate items, but with hyperlinks that makes it easy to switch between them:
Something like this:
Example Interface
Related to: Example Class
The mixin base class for declarations that have an associated release tag.
Signature:
interface Example
Pete and I were discussing ways that TSDoc can handle merged declarations, and wanted to summarize a couple ideas here.
Say you have a scenario where you want to export the same API with a different name. You could have something like
where Y is an enum. For certain reasons, we are considering splitting it up into something like the following instead:
We likely still want both X's to be documented together. We have two tags in mind to solve this:
@documentAs
and@partOf
.@documentAs
would be used to tell the documentation system how to present this API, for example grouping it under the "Enums" section even though it isn't technically an enum.@partOf
would be used to group the second definition with the first.Using the example above, we might have something like the following:
I'm curious to see if anyone else has thought about this much and/or has any other ideas or suggestions.