Declaration references
Certain tags such as {@inheritdoc}
and {@link}
can refer to other API items such as classes, member functions,
enum values, etc. The referenced item may be local, or it may be imported from an external NPM package.
It could be part of a merged declaration or an overloaded function.
The TSDoc syntax provides a special "declaration reference" notation for unambiguously identifying declarations in all these situations. (This aspect of TSDoc is still evolving; it is tracked by RFC #9. The current spec is outlined in code-snippets/DeclarationReferences.ts.)
Syntax Examples
Below are syntax examples that should help you get started writing declaration references.
A simple local declaration
/** @public */
export class Widget {
/**
* Call this before calling the {@link Widget.render | the render() method}.
*/
public initialize(): void {}
public render(): void {}
}
To refer to a declaration in the same project, simply use its name, with a "." to scope any nested members.
In the above example, Widget.render
refers to the render
method of the Widget
class. As long as the match
is unambiguous, it doesn't matter whether the member is static
or not.
TSDoc declaration references are always resolved relative to a specific entry point (NOT relative to the current source file or declaration scope). Thus, their syntax is independent of where the reference occurs within a given package. Since
Widget.initialize
appears insideWidget
, we may want to shorten the reference to{@link render | the render() method}
, but TSDoc standard does not support this.
An imported declaration
import { Widget } from '@my-org/widget-lib';
/**
* Returns a new instance of the {@link @my-org/widget-lib#Widget} class.
* @public
*/
export function createWidget(): Widget {
. . .
}
To refer to a declaration that is imported from an NPM package, specify the package name followed by a #
character (e.g. widget-lib#Widget
). If the package name has an NPM scope, it can be included
as well (e.g. @my-org/widget-lib#Widget
).
An entire package
import { Button } from 'controls';
/**
* Constructs a `Button` as defined by the {@link controls#} library.
* @public
*/
export function createButton(): Button {
. . .
}
To refer to the entire package (rather than a particular export), simply omit the member name as shown above.
You must include the #
character, however, since otherwise controls
looks like a reference to a declaration
with that name.
A merged declaration
/** @public */
export enum ShirtSize {
Small,
Medium,
Large
}
/** @public */
export namespace ShirtSize {
/**
* Parses a string and returns an instance of the
* {@link (ShirtSize:enum)} enum.
*/
export function parseName(name: string): ShirtSize {
switch (name) {
case 'S':
return ShirtSize.Small;
case 'M':
return ShirtSize.Small;
case 'L':
return ShirtSize.Large;
}
throw new Error('Invalid size');
}
}
In the above example, the symbol ShirtSize
is both an enum and a namespace. If we simply wrote {@link ShirtSize}
then API Extractor would report a warning like this:
Warning: (ae-unresolved-link) The @link reference could not be resolved:
The reference is ambiguous because "ShirtSize" has more than one declaration;
you need to add a TSDoc member reference selector
The (ShirtSize:enum)
notation uses a TSDoc system selector to clarify that we're talking about the enum,
not the namespace.
Unsupported Features
API Extractor supports all the core features of TSDoc declaration references, but does not yet support some advanced features that are described in the spec:
- Index selectors
- Label selectors
- References using ECMAScript symbols instead of identifiers
- Import paths
These features may be implemented in the future. If you'd like to contribute, take a look at the code in AstReferenceResolver.ts and ModelReferenceResolver.ts.