Open octogonz opened 6 years ago
This tag seems to still be useful for properties and fields. It seems less applicable for function parameters with the introduction of default values accessible in the AST with ES6+ and TS. However, it's still applicable on the JS side of things IMHO due to call time evaluation and default parameters being available for later evaluation (examples taken from here):
function callSomething(thing = something()) {
return thing;
}
function something() {
return 'sth';
}
or default parameters being available to later default parameters
function singularAutoPlural(singular, plural = singular + 's', rallyingCry = plural + ' ATTACK!!!') {
return [singular, plural, rallyingCry];
}
Granted JS examples on tricky edge cases, but likely as well w/ TS? The @param w/ types and default values
JSDoc syntax handles this for function parameters. It would be interesting to see the TS counterpart to the above perceived edge cases.
The examples above would cause trouble for various documentation tooling pipelines likely as resolving things requires a two pass algorithm and potential evaluation which can be fragile where the @default
@param w/ default values
syntax provides up front clarification.
Based on the discussion with office-ui-fabric-react, we're thinking @default
tag would have the following spec:
@default
should NOT be applied to a function or class declaration.Usage example:
enum WarningStyle {
DialogBox,
StatusMessage,
LogOnly
}
interface IWarningOptions {
/**
* Determines how the warning will be displayed.
*
* @remarks
* See {@link WarningStyle| the WarningStyle enum} for more details.
*
* @default `WarningStyle.DialogBox`
*/
warningStyle: WarningStyle;
/**
* Whether the warning can interrupt a user's current activity.
* @default
* The default is `true` unless
* `WarningStyle.StatusMessage` was requested.
*/
cancellable?: boolean;
/**
* The warning message
*/
message: string;
}
I noticed that although JSDoc supports @default
as shown above, it also allows @default
to act as a modifier tag that instructs a documentation engine to show the assigned value of a variable. This is the example they give:
Document the number value of a constant
/**
* @constant
* @default
*/
const RED = 0xff0000;
I interpret this to mean that, JSDoc parses @default
as a block tag if there's more text on the same line, otherwise it's parsed as a modifier tag. Since TSDoc doesn't force each tag to be on its own line, this is unconventional and likely to cause confusion.
I'm also not even sure this is needed with TypeScript. In my experience the type system already makes it fairly easy to determine whether or not a variable is a constant whose value should be documented.
Since JSDoc defines @defaultvalue
as a synonym, I propose the following refinements:
TSDoc should use @defaultValue
(block tag) for the original scenario we discussed ONLY. The name @defaultValue
makes it more obvious that you must provide some text.
TSDoc should reserve @default
(modifier tag) as a "discretionary" tag. Its exact meaning will be left to implementors, but by saying that it's a modifier tag, we're clear that the text after it cannot be treated as an argument.
This ensures that the two scenarios don't get confused, and we won't need a special grammar rule to handle this tag.
Updated usage example:
enum WarningStyle {
DialogBox,
StatusMessage,
LogOnly
}
interface IWarningOptions {
/**
* Determines how the warning will be displayed.
*
* @remarks
* See {@link WarningStyle| the WarningStyle enum} for more details.
*
* @defaultValue `WarningStyle.DialogBox`
*/
warningStyle: WarningStyle;
/**
* Whether the warning can interrupt a user's current activity.
* @defaultValue
* The default is `true` unless
* `WarningStyle.StatusMessage` was requested.
*/
cancellable?: boolean;
/**
* The warning message
*/
message: string;
}
@kkjeer
Related TypeStrong/typedoc#856
Typedoc show values but in some cases that isn't desired, such as here when the text is super long.
@octogonz How about documenting default function parameters? What will that look like?
How about documenting default function parameters? What will that look like?
@sindresorhus After thinking about this question, I don't think @defaultValue
is the right tag for this. I opened a separate GitHub issue to discuss your question: https://github.com/Microsoft/tsdoc/issues/151
Hi @octogonz , sorry don't know where to ask, hope this would be a good place.
You've outlined that @defaultValue
should be used only for classes or interfaces. What about type? It's quite often used in React-land, for defining props via type instead of interface, as sometime it gives better flexibility, and it may have a default value. In separate thread that you have for function default values it's not really applicable I think.
Let me provide you an example:
const enum ButtonType {
DEFAULT = 'default',
PRIMARY = 'primary'
}
type ButtonProps = {
/**
* This is identify Button type
* @defaultValue? ButtonType.DEFAULT
*/
type?: ButtonType;
children: React.ReactNode;
} & Omit<JSX.IntrinsicElements['button'], 'children'>;
const Button = ({ type, children, ...props }: ButtonProps) => {
const type = type ?? ButtonType.DEFAULT;
return <button className={mapTypeToClassName(type)} {...props}>{children}</button>;
};
This is quite common approach for declaring React component props, and as you see function has no default parameters, at least in obvious way, so my question is, should it be ok to use @defaultValue
for the type's as well? Or should be some other tag introduced?
Short answer: Yes @defaultValue
is okay.
Long answer: My perspective comes from projects where we are designing third-party APIs with an API documentation website. So I would try to write it something like this:
interface IButtonCoreProps {
/**
* This is identify Button type
* @defaultValue? ButtonType.DEFAULT
*/
type?: ButtonType;
children: React.ReactNode;
};
type ButtonProps = IButtonCoreProps & Omit<JSX.IntrinsicElements['button'], 'children'>;
The reason is that an interface
is a familiar stereotype that can be nicely displayed on a documentation website, with nice sections for each its interface members.
Whereas type
is a mishmash of arbitrary type algebra. It contains a sort of "interface" buried in there (that @defaultValue
could apply to), but a documentation tool would see it as an amoeba whose structure may change whenever a developer expands it with some more type subexpressions. Thus as an API designer I strongly prefer stereotypical patterns (interface
, class
, function
, etc) instead of mishmashes of type algebra.
But these concerns maybe aren't relevant to your case. The ButtonProps
type may be some internal app code that does not need to be displayed as a nice API manual. And React's "props" system is a widely understood pattern that establishes some proprietary stereotypes of its own. So in that context your more concise notation is perhaps better.
Maybe the TSDoc spec should say it in a more general way, like: @defaultValue
is meant for optional properties of interface
members, or other type expressions that behave like interfaces.
I'm reluctant for TSDoc to specify stereotypes. They seem like an implementation detail that may vary between documentation tools. For example, one tool might consider this to be a "function":
/**
* @param x - the input
* @returns the result
*/
const f: (x: string) => string;
Another tool may consider it to be a "variable" whose value is a mishmash of algebra.
What about this thing below?
/**
* Some docs
*/
const f:
/**
* @param x - the input
* @returns the result
*/
((x: string) => string) |
/**
* @param x - the input
* @returns the result
*/
((x: number) => number);
Is that two "functions" in there? API Extractor would consider it a misuse of TSDoc. But if some other tool has a way to present (x: number) => number)
as being a "function" in some meaningful way, it feels wrong for TSDoc to specify that no, nobody should do that.
Perhaps what we should specify is a minimal set of "core" stereotypes that all TSDoc implementors should be expected to recognize. If you write doc comments using those patterns, you know they will have consistent behavior everywhere.
In API Extractor issue #720 @RueDeRennes asked about supporting
@default
to indicate a default value.Some questions:
@default
or@defaultValue
?