microsoft / tsdoc

A doc comment standard for TypeScript
https://tsdoc.org/
MIT License
4.71k stars 131 forks source link

Discussion: How to document inferred types using TSDoc #241

Open jayarjo opened 4 years ago

jayarjo commented 4 years ago

I have a complex type that is inferred from yup schema, so something like:

export type Config =  y.InferType<typeof isConfig>

How would one ts-doc its properties manually?

octogonz commented 4 years ago

Could you share a more complete example that includes the definition of y and isConfig?

octogonz commented 4 years ago

FYI this came up recently in a discussion https://github.com/microsoft/rushstack/issues/1874#issuecomment-633883380 for the API Extractor project, where someone was using the purify library to model JSON objects. (Probably it's related to your case here.)

There does not seem to be a straightforward way to generalize JSDoc-style doc comments to handle those types. My initial opinion was that complex inferred types are perhaps not the best way to represent an API contract that we want to document. 🙂 I have a personal bias, though. My bandwagon is to build software systems that are easy for strangers and beginners to learn and contribute to. Thus I would happily sacrifice conciseness and mathematical elegance in favor of coding patterns that are simple and avoid TypeScript's growing list of higher order operators and inferences. I don't mean to discourage complex types really, merely to say I have not explored this much myself.

There is a clear trend of developers who want to make these elaborate and heavily abstracted type declarations. It includes the TypeScript compiler owners, so this actually characterizes the TypeScript language to some extent. It would be great for TSDoc to support it.

If people have ideas, here's a good place to share them.

@rbuckton FYI

jayarjo commented 4 years ago

It's more about not having to update types in several places rather than elegance. Here's the slice of type that is generated and exported to corresponding d.ts file:

declare const isConfig: y.ObjectSchema<{
    image: string;
    name: string;
    env: object;
    buildArgs: object;
    exposedPorts: any;
    networkMode: string;
    bindMount: any;
    startupTimeout: number;
    cmd: string;
    healthCheck: any;
    auth: any;
    useDefaultLogDriver: boolean;
}>;
octogonz commented 4 years ago

Let us suppose that you wrote TSDoc comments like this:

declare const isConfig: y.ObjectSchema<{
    /**
     * the URL of the image
     */
    image: string;
    /**
     * the name of the thing
     */
    name: string;
    /**
     * additional environment variables to be passed along
     * @remarks
     * These should be mapping of string keys to string values.
     * @defaultValue `undefined`
     */
    env: object;
    . . .

Now, the documentation tool would need to somehow analyze the compiler's inferred type for y.InferType<typeof isConfig> and trace it back to those original declarations.

And the analysis would need to understand that string in the expression image: string; is not TypeScript's string. Confusingly this string is an imported JavaScript object with the same name (that causes the inferred type to become a TypeScript string).

But in the end, the doc comments here could be mapped to the inferred property signatures that they produce. And then pretty much the normal TSDoc rules would apply.

In fact, the TypeScript compiler could do most of the work for us, by emitting the inferred type in the .d.ts file, with the doc comments preserved in place.

Thinking about it that way, this discussion is not really about "complex" types. Rather the problem here is:

Where do you write comments for an inferred type, since it has no explicit source code?

And maybe the answer could be: On whatever thing that it was inferred from. And it's up to the compiler or documentation tool to figure out how to find that thing.

jayarjo commented 4 years ago

I mean the same way we have @param, which overrides inferred definition, if present, we could have @property. Then we could write comments anywhere.

octogonz commented 4 years ago

@jayarjo Are you proposing something like this?

/**
 * @property image - the URL of the image
 * @property name - the name of the thing
 * @property env - additional environment variables to be passed along
 */
export type Config =  y.InferType<typeof isConfig>

This does not seem like it would work very well:

jayarjo commented 4 years ago

@octogonz

  1. that's what doc parser can try to determine itself
  2. how do you structure them for @param?