microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.33k stars 12.4k forks source link

Richer Diagnostic Display Meta-Issue #41860

Open DanielRosenwasser opened 3 years ago

DanielRosenwasser commented 3 years ago

This issue tracks a couple of different useful ideas for making diagnostics "richer" for display purposes. We've wanted some of these for a while, and they're partially inspired by testing tools like Jest and Mocha. We've also seen tools like Rust, Rome, and Flow prove them out to some extent.

Long-term, you could imagine them being interactive with the a richer compiler client.

Printing Messages Across Lines

Types can get unwieldy, and displaying them inline makes it harder to see where things begin/end.

Type

    { x: string, y: number }

is not assignable to

    { x: string, y: string }

Notice no punctuation at the end. Not sure if we can generalize messages that way.

Also not sure how this plays well with

Highlighted Spans in Messages

Imagine being able to highlight individual sections inside of types to indicate where the issue occurs.

                              vvvvvvvvvvv
Type '{ a: string; b: number; c: boolean; }' is not assignable to type '{ a: string; b: number; }'.
                              ^^^^^^^^^^^
  Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.

Diff Highlighting in Messages

Basically imagine red being the provided color, with green being an expected color.

Type '[string, number, boolean]' is not assignable to type '[string, string, boolean]'.
               ^^^^^^                                                ^^^^^^
               rrrrrr                                                gggggg
weswigham commented 3 years ago

I think adding extra lines of (potentially colored) text (and linebreaks) under --pretty style output is probably safe (since the file name/line/error code is what vscode matches matches on, since that's the only "stableish" part of the message).

DanielRosenwasser commented 3 years ago

@dbaeumer may have some more knowledge on potential problem matcher issues, but I know other tools split messages across multiple lines too.

dbaeumer commented 3 years ago

Passing on to @alexr00 (tasks do have multi line matchers but I am not sure what the current state is)

alexr00 commented 3 years ago

Here's the documentation on multiline problem matchers in VS Code, but I don't think you'd need them if you're only adding extra lines: https://code.visualstudio.com/Docs/editor/tasks#_defining-a-multiline-problem-matcher

Adding extra lines that don't need to read by a VS Code problem matcher should just be ignored by the existing typescript problem matcher.

DanielRosenwasser commented 3 years ago

Another one: smarter truncation don't elide the parts that are actually gonna be elaborated on (@RyanCavanaugh calls this "differential typeToString" and wants to prototype it).

DanielRosenwasser commented 3 years ago

I opened up #42597 to track that, since it's not as relevant to richer diagnostic display - it's more of a type display strategy.

JoshuaKGoldberg commented 3 years ago

@DanielRosenwasser I'd be very interested in contributing here. Are there particular parts of this that could already be split out into Help Wanted tasks?

jleider commented 3 years ago

Regarding Suggestion 1

An idea that my team has kicked around is a way to turn very large nested types into a pretty json like format. Instead of the whole type appearing on a single line, it would be pretty printed so each nesting level would be indented. For small types, the single line is not really a big deal, its when you are working with large nested objects that the errors become an unreadable wall of text.

For example if the original example was augmented with nested objects:

Type

    { x: string, y: number, o: { a: string, o2: { b: number, c: boolean } } }

is not assignable to

    { x: string, y: string }

It could be shows as follows:

Type

    { 
        x: string, 
        y: number, 
        o: { 
            a: string, 
            o2: { 
                b: number, 
                c: boolean 
            } 
        } 
    }

is not assignable to

    { 
        x: string, 
        y: string 
    }

Regarding Suggestion 2

Regarding the second type highlighting example, this would be my preferred outcome of this PR. However, if thats not possible a poor cousin of that would be just highlighting the two different types. Again when the types are small, it's not really a big deal, but when you are hunting for the part in the error where it says is not assignable to type in a giant wall of text is where colors make a big deal.

Here is an example of how it could look:

image

I have a proof of concept that I've been using with my team for the last couple weeks and this surprisingly small change helps a lot scanning the errors. https://github.com/jleider/ts-error-formatter

typeholes commented 10 months ago

I have been playing with including the diagnostic arguments in the diagnostics with a type of

{ text: string, type: 'Node'|'Type'|'string', cacheId: number }

and adding a function to fetch the relevant object by the cache id. This enables a lot of functionality for displaying and interacting with error messages. For example, I use it to allow the user to expand a type or display the value declaration of a symbol. The big upshot is flexibility - Diagnostic functionality is not limited to what is baked into typescript.

Is this issue a good place to discuss this approach, or should I open a new one?