In issue https://github.com/Microsoft/tsdoc/issues/27#issuecomment-473178150 , @sindresorhus asked:
How about documenting default function parameters? What will that look like?
I've opened a new issue since I think it's a separate topic from the @defaultValue tag.
My initial instinct would be to say that TSDoc should not be involved with parameter defaults, because the information is already clearly expressed in the source code.
For example:
chart.ts
/**
* Add a series to the chart
* @param formatString - the label to show for the new series
* @param options - additional options
*/
export function addSeries(formatString: string = "The ${title} series",
options: IOptions = { dataSource: "default" }): void {
// ...
}
But there's a hitch. The TypeScript compiler does not propagate this information into the generated .d.ts files. For example, you might get output like this:
chart.d.ts
/**
* Add a series to the chart
* @param formatString - the label to show for the new series
* @param options - additional options
*/
export declare function addSeries(formatString?: string, options?: IOptions): void;
The .d.ts files are often the only file you ship to consumers of your library. So it does seem that the doc comments need to express this somehow.
I went and looked at JSDoc for comparison. Their @param tag spuports a special notation for this. It uses [] to indicate an optional parameter (which is redundant in TypeScript, but is maybe a useful grouping mechanism). And it uses = to indicate the default value. If we follow that approach, we'd get something like this:
/**
* Add a series to the chart
* @param [formatString=The ${title} series] - the label to show for the new series
* @param [options={ dataSource: "default" }] - additional options
*/
export declare function addSeries(formatString?: string, options?: IOptions): void;
This could work, however TSDoc seeks to be a rigorous and syntactically complete language. I have a number of design questions about JSDoc's notation:
Why aren't string literals enclosed in quotes? For example, if the "The ${title} series" string happened to be the text string "{ dataSource: "default" }" then without quotes we can't distinguish it from the object notation used by the options parameter. Or what the title was "] -"? Without quotes, there's no way to distinguish those characters from @param delimiters.
If strings are quoted, obviously we need to support \ escape characters, otherwise you can't have a " character as your default value.
Which quoting styles are allowed? In TypeScript we have ', ", and `
What other kinds of expressions are allowed for the default value? For example, a TypeScript parameter default value can include operators (e.g. "hello" + " world") and even function calls (e.g. f("hello").trim()). That seems a little excessive for documentation, and it would require TSDoc parsers to include a full JavaScript subgrammar, which is costly. So we'd need to restrict it down somehow.
Can the value expression span multiple lines? If so, then we need to design the rules carefully to ensure that if someone types an invalid expression, the parser won't consume an arbitrary amount of text. Otherwise the syntax highlighter can weirdly highlight too much stuff, or parsing may be inefficient.
Is this something that should be changed in .d.ts files? I'm not sure either way but if TypeScript already can communicate it, why would we want to move that into the doc comment?
Is this something that should be changed in
.d.tsfiles? I'm not sure either way but if TypeScript already can communicate it, why would we want to move that into the doc comment?
@aciccarello It certainly seems so. But we can also ask a similar question about why decorators are not represented in the .d.ts files (since libraries like Angular use them extensively to describe API contracts). My guess is that in both cases, these expressions can incorporate arbitrarily complex executable code, so there's a slippery slope regarding to what extent it can/should be represented in the type declaration.
A more pathological example:
function square(x: number): number {
return x * x;
}
function add(
x: number,
y: number,
z = [x, square(x)].reduce((x, y) => x + y)
): number {
return x*z;
}
@DanielRosenwasser @RyanCavanaugh who may have a more informed opinion than me. :-)
On the other hand, the above discussion shows that if we push the problem onto TSDoc, it doesn't seem to get much easier. Well... unless we take the escape hatch (no pun intended) of saying that TSDoc's default values are not parsed as TypeScript code at all. They are merely blobs of documentation text. If we go that route, then the problem transforms into a simpler problem of character escaping: How do you delimit a string containing a lot of symbol characters without a ton of backslash escapes everywhere?
I suppose we could simply rely on Markdown:
/**
* Add a series to the chart
* @param formatString = `"The ${title} series"` - the label to show for the new series
* @param options = `{ dataSource: "default" }` - additional options
*/
export function addSeries(formatString: string = "The ${title} series",
options: IOptions = { dataSource: "default" }): void {
// ...
}
This feels reasonable at first, although I can raise a bunch of design questions for it as well:
` character that Markdown provides no way to escape? (Fortunately TSDoc already has to solve this one elsewhere.)If people like this idea, it is easier I think. These problems are the kind of thing TSDoc deals with every day heheh.
Instead of adding functionality to tsdoc to handle default function parameters, I'd much rather just infer the default value from the function definition itself.
But there's a hitch. The TypeScript compiler does not propagate this information into the generated .d.ts files. For example, you might get output like this:
Couldn't we have tsdoc only infer this type of information if run on the original source files? I feel like this is the main use case for tsdoc as opposed to running on third-party .d.ts files.
Couldn't we have
tsdoconly infer this type of information if run on the original source files? I feel like this is the main use case fortsdocas opposed to running on third-party.d.tsfiles.
I was mainly thinking about it from the perspective of API Extractor, one of the biggest implementers of TSDoc. API Extractor analyzes the output of the TypeScript compiler (.d.ts files), rather than the original source files (.ts files). This was an intentional design decision, but other documentation tools are free to analyze the .ts files however they like. TSDoc is mainly a standard for how doc comments are parsed, so it doesn't say a lot about how TypeScript signatures get analyzed.
If your documentation tool reads the .ts files, then it's perfectly acceptable to extract the parameter default values from the source code. But then you wouldn't need any help from TSDoc, so this RFC wouldn't be relevant.
If your documentation tool reads the .ts files, then it's perfectly acceptable to extract the parameter default values from the source code. But then you wouldn't need any help from TSDoc, so this RFC wouldn't be relevant.
Got it -- thanks!
In that case, I'd prefer @aciccarello's proposal to push this information into the .d.ts files which seems like the KISS solution here.
Most helpful comment
Is this something that should be changed in
.d.tsfiles? I'm not sure either way but if TypeScript already can communicate it, why would we want to move that into the doc comment?