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

Ways for pure JavaScript consumers to obtain type information from TypeScript libraries #120

Open
octogonz opened this issue Oct 25, 2018 · 6 comments
Labels
general discussion Not a bug or enhancement, just a discussion

Comments

@octogonz
Copy link
Collaborator

octogonz commented Oct 25, 2018

@liamross brought up an interesting scenario in #115:

However, the fact that my documentation will have zero indication of the type of a parameter means that this could never serve as a replacement for JSDoc for me personally. If I write a library in TypeScript and it is consumed by a JavaScript application, I would like for there to be typings in the documentation, and not require that people are relying on IDE tooling or digging into the package to find types.

The first thing that drew me to this was the idea of it parsing types from the code to save the redundant declarations in the documentation.

If you build a library in TypeScript, the output includes declaration files (*.d.ts) that provide very accurate type information. (Arguably the best in the world! :-) ) However many JavaScript tools perform static type analysis based on .js files, and ignore the .d.ts files.

These tools generally expect to obtain their type information from JSDoc tags such as this sample that I pulled from a random blog post:

    /** @namespace */
    var util = {
        /**
         * Repeat <tt>str</tt> several times.
         * @param {string} str The string to repeat.
         * @param {number} [times=1] How many times to repeat the string.
         * @returns {string}
         */
        repeat: function(str, times) {
            if (times === undefined || times < 1) {
                times = 1;
            }
            return new Array(times+1).join(str);
        }
    };

The TypeScript equivalent would look like this:

/** @namespace */
export namespace util {
  /**
   * Repeat <tt>str</tt> several times.
   * @param {string} str - The string to repeat.
   * @param {number} [times=1] - How many times to repeat the string.
   * @returns {string}
   */
  export function repeat(str: string, times: number = 1): string {
    if (times === undefined || times < 1) {
      times = 1;
    }
    return new Array(times + 1).join(str);
  }
}

The JSDoc annotations such as @namespace, {string}, [times=1] are redundant because we already expressed all those things using type declarations. It would be annoying for developers to have to declare everything twice. And it would be error-prone because TypeScript developers generally don't rely on the JSDoc tags themselves, so they won't notice mistakes. (In my own anecdotal experience migrating code bases, I've found that these redundant tags are very frequently incorrect or inconsistent with the TypeScript types.)

The compiler does support JSDoc type annotations, so one possible idea would be for people to use JSDoc annotations instead of type declarations for the public parts of their API, since these annotations do end up in the emitted .js files. However this would be limiting, since JSDoc's type expressions are quite limited compared to all the things you can express in TypeScript. And it would be an awkward developer experience.

The "ideal" solution would be to improve the JavaScript tools to support .d.ts files when they consume a TypeScript library. But let's assume that's impractical for various reasons. What other approaches could we use, and can TSDoc help somehow?

@octogonz
Copy link
Collaborator Author

One possibility would be a compiler feature (or plugin?) that emits JSDoc type annotations in the output .js files, based on the compiler's type analysis. (I suspect this is closely related to another recent discussion, where people wanted the compiler to read plain .js files and generate .d.ts files based on its analysis.)

If the TypeScript source code has TSDoc comments, then in this approach the compiler would need to combine the TSDoc documentation with the type annotations to produce a JSDoc output.

It's tempting to expand the TSDoc language to optionally support every last JSDoc type annotation, and then the @microsoft/tsdoc library could be used to emit the JSDoc. However I'm sure there already exist plenty of specialized libraries for generating JSDoc, which do that very well, and are focused around that scenario. Keep in mind the goal is maximum compatibility with legacy JavaScript tools that are probably unable to adapt their parsers for this scenario. So I wonder to what extent the TSDoc input really needs to be consistent with the emitted JSDoc output.

What do you think? If someone has firsthand experience with this scenario, maybe they could provide some details.

@octogonz octogonz added the general discussion Not a bug or enhancement, just a discussion label Oct 25, 2018
@aciccarello
Copy link

Related: microsoft/TypeScript#10

@liamross
Copy link

Hey thanks for extending this into an issue! Let me just elaborate a bit on what a dream scenario would be for me personally. Here's an example from the playground, but with typing included in the TypeScript. Note that as you mentioned above, ideally the typings would not be repeated in the actual documentation:

/**
 * Returns the average of two numbers.
 *
 * @remarks
 * This method is part of the {@link core-library#Statistics | Statistics subsystem}.
 *
 * @param x - The first input number
 * @param y - The second input number
 * @returns The arithmetic mean of `x` and `y`
 *
 * @beta
 */
function getAverage(x: number, y: number): number {
  return (x + y) / 2.0;
}

And here is an example of the documentation that said code would generate:


Summary

Returns the average of two numbers.

Parameters

Name Type Description
x number The first input number
y number The second input number

Return Value

Type Description
number The arithmetic mean of x and y

Remarks

This method is part of the Statistics subsystem.

Modifiers

@beta

@liamross
Copy link

What I'm not sure about is whether that would be unreasonably difficult to implement, or whether that is even a requirement / goal of this project.

@octogonz
Copy link
Collaborator Author

@liamross Hrmmm... I'm a little confused by your latest comment. What would the expected output look like for the .js files?

I'm reachable on Gitter if you want to chat directly.

@octogonz
Copy link
Collaborator Author

We chatted about this. @liamross clarified that for now he's mainly interested in generating web site documentation. I suggested to take at API Extractor or TypeDoc, both of which are complete documentation tools (whereas @microsoft/tsdoc is just the parser). They use the TypeScript compiler engine to crawl your library's API, and then generate a documentation web site based on your doc comments. API Extractor 6 has already integrated the TSDoc parser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
general discussion Not a bug or enhancement, just a discussion
Projects
None yet
Development

No branches or pull requests

3 participants