microsoft / TypeScript

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

Setting noErrorTruncation to false truncates inferred type of variables/functions; which are not errors #26238

Open AnyhowStep opened 6 years ago

AnyhowStep commented 6 years ago

TypeScript Version: 3.0.1

Search Terms: noErrorTruncation

In TS 2.9, if noErrorTruncation is unset, or set to false, hovering the cursor over an identifier for type inference in VS code would bring up a tooltip with the inferred type.

In TS 3.0, if noErrorTruncation is unset, or set to false, the tooltip with the inferred type will be truncated with ellipsis.

Code

TS 2.9, with noErrorTruncation : false

    /*snip*/
    __canAccept: {
        page?: string | number | null | undefined;
        itemsPerPage?: string | number | null | undefined;
    };
}

TS 3.0 with noErrorTruncation : false

    /*snip*/
    __canAccept: {
        ...;
    };
}

Expected behavior:

noErrorTruncation is about truncating errors.

The tooltips displaying inferred types aren't errors, and should not be affected by this flag.

Actual behavior:

noErrorTruncation affects tooltips displaying inferred types.


If anyone else is having this problem, just go to your tsconfig.json, add the following line,

"noErrorTruncation": true,

and restart VS code (or your editor of choice)

AnyhowStep commented 6 years ago

Weird. I thought I finally "fixed" it but, even with noErrorTruncation turned on, some long and complicated types still show up with ellipsis.

Is there a noInferredTypeTruncation thing I'm missing?


Turning on noErrorTruncation certainly stops some truncations, but it still doesn't prevent others.

TomaszWaszczyk commented 5 years ago

Weird. I thought I finally "fixed" it but, even with noErrorTruncation turned on, some long and complicated types still show up with ellipsis.

The same for me. TypeScript 3.2.2

AnyhowStep commented 5 years ago

I'm pretty sure it has something to do with createElidedInformationPlaceholder

weichensw commented 5 years ago

The ellipses makes it very hard to debug Pick, Omit, etc, when things went wrong.

aleclarson commented 5 years ago

@xbtsw Using "noErrorTruncation": true works perfectly on my end. (typescript v3.4.3)

edit: Something like noInferredTypeTruncation would be great! 👍

weichensw commented 5 years ago

@aleclarson maybe I should say “when things not went as intended”. As you probably noticed the problems not always manifest itself as an error. Sometimes debugging is done by hovering on an inferred type.

AnyhowStep commented 5 years ago

I'm still on 3.5.1.

This is kind of blocking my attempts at continuous integration =/

I do a character-by-character comparison of messageText for output errors, for my compile-time tests. I remove the working directory from import("...") types but the type names keep getting truncated at arbitrary places.

So, different working directory name lengths = different ellipsis positions = failing CI

If noErrorTruncation didn't truncate types in errors, I'd be passing CI. I guess I'll just ignore messageText in CI for now...

Ciantic commented 4 years ago

It's not just CI, it's usability problem. I actually like browsing (and copying) the type from the hover tip in the VSCode, and when it gets truncated it's pretty much useless.

image

```typescript // from https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/intro-to-tweet-json let foo = { "text": "My added comments to this Tweet ---> https:\/\/t.co\/LinkToTweet", "user": { "screen_name": "TweetQuoter" }, "quoted_status": { "text": "original message", "user": { "screen_name": "OriginalTweeter" }, "place": { }, "entities": { }, "extended_entities": { } }, "place": { }, "entities": { "hashtags": [ ], "urls": [ { "url": "https://t.co/W1FqVrsjQk", "expanded_url": "https://twittercommunity.com/t/rt-with-comment-aka-quote-tweets-now-may-have-media-attached-across-twitter-apis/125539", "display_url": "twittercommunity.com/t/rt-with-comm…", "unwound": { "url": "https://twittercommunity.com/t/rt-with-comment-aka-quote-tweets-now-may-have-media-attached-across-twitter-apis/125539", "status": 200, "title": "RT with comment, aka Quote Tweets, now may have media attached across Twitter APIs", "description": "Today we’re announcing a new feature that allows userspeople on Twitter to add a GIF, video, or photo to their Retweet with comments, aka Quote Tweets. Developers will start to see additional media metadata included in the payload for Quote Tweets. Quote Tweets with media will be rendered very similarly to Tweets with media across our APIs. This rendering is an addition to the existing media field, so this should not be a breaking change for application owners, if they are already ingesting med..." }, "indices": [ 162, 185 ] }, { "url": "https://t.co/lXs26mCkIl", "expanded_url": "https://twitter.com/TwitterSupport/status/1125479034513645569", "display_url": "twitter.com/TwitterSupport…", "indices": [ 186, 209 ] } ], "user_mentions": [ ], "symbols": [ ], "media": [ { "id": 1125490782532657153, "id_str": "1125490782532657153", "indices": [ 210, 233 ], "media_url": "http://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg", "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg", "url": "https://t.co/T9MBCHZWcD", "display_url": "pic.twitter.com/T9MBCHZWcD", "expanded_url": "https://twitter.com/TwitterDev/status/1125490788736032770/photo/1", "type": "animated_gif", "video_info": { "aspect_ratio": [ 101, 165 ], "variants": [ { "bitrate": 0, "content_type": "video/mp4", "url": "https://video.twimg.com/tweet_video/D56L51LV4AEEC8-.mp4" } ] }, "sizes": { "thumb": { "w": 150, "h": 150, "resize": "crop" }, "small": { "w": 202, "h": 330, "resize": "fit" }, "large": { "w": 202, "h": 330, "resize": "fit" }, "medium": { "w": 202, "h": 330, "resize": "fit" } } } ] }, "extended_entities": { "media": [ { "id": 1125490782532657153, "id_str": "1125490782532657153", "indices": [ 210, 233 ], "media_url": "http://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg", "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/D56L51LV4AEEC8-.jpg", "url": "https://t.co/T9MBCHZWcD", "display_url": "pic.twitter.com/T9MBCHZWcD", "expanded_url": "https://twitter.com/TwitterDev/status/1125490788736032770/photo/1", "type": "animated_gif", "video_info": { "aspect_ratio": [ 101, 165 ], "variants": [ { "bitrate": 0, "content_type": "video/mp4", "url": "https://video.twimg.com/tweet_video/D56L51LV4AEEC8-.mp4" } ] }, "sizes": { "thumb": { "w": 150, "h": 150, "resize": "crop" }, "small": { "w": 202, "h": 330, "resize": "fit" }, "large": { "w": 202, "h": 330, "resize": "fit" }, "medium": { "w": 202, "h": 330, "resize": "fit" } } } ] } }; ```
asanacam commented 4 years ago

noErrorTruncation also does not solve this problem for me.

bradennapier commented 4 years ago

Yes agree here, it would be huge to at least have some tool - perhaps even something dedicated that would allow us to see the fully expanded and normalized type that typescript will use. Perhaps a custom "peek" style popup for it so that we can choose to view it only when we need to in the case of large types that would make processing type extreme.

lake2 commented 4 years ago

same issue +1 Any way to solve this?

weichensw commented 4 years ago

The ellipsis makes it especially difficult to debug type issues (not type errors) involving Pick, Omit etc.

For example in a type that involves Omit I made a typo in second parameter of Omit, then in some other place I wondered why a interface property is still accepted. The ellipsis makes it difficult to trace back and find the original typo.

MattiasMartens commented 4 years ago

This is an issue that keeps popping up for me. Any motion on it?

Hati- commented 4 years ago

Having this problem as well. Investigating and debugging this issue led me to find this being introduced in merge https://github.com/microsoft/TypeScript/pull/24258.

Typescript starts truncating the output when it reaches the default hard-limit of 160 * 10 characters to prevent the server from hanging too long, even with "noErrorTruncation": true set. There's currently no option for VS Code to disable it from the looks of it: https://github.com/microsoft/TypeScript/blob/57e2fe0462bb897e581aa489f1d6040db559d82b/src/services/utilities.ts#L1993

For people using VS Code, a quick fix would be opening <Microsoft VS Code install folder>/resources/app/extensions/node_modules/typescript/lib/tsserver.js and change ts.defaultMaximumTruncationLength = 160 at around line 12797 to something higher like ts.defaultMaximumTruncationLength = 800.

MattiasMartens commented 4 years ago

Thank you for your efforts sleuthing this out @Hati- !

I would hope to see this value bound as a configurable TS preference. However it is awesome to know that there is a way to hack around the limitation.

jdmoody commented 3 years ago

Thanks again for the hack!

I just wanted to call out that if your VSCode config specifies the "typescript.tsdk" option, you'll need to update the tsserver.ts in whatever location that option specifies. It would have saved me a bit of debugging time 🙃

devuxer commented 2 years ago

The hack is good to know about, but it isn't really a solution for me. What I'm running into is that I often want to hover a type and want see the entire type (no "..."), but when I'm trying to read an error, showing entire type definitions can sometimes make the error utterly unreadable. So, some finer grained control is really needed here. Ideally, there'd be some integration between TypeScript and VSCode to provide a toggle to choose between "verbose" (types expanded) and "compact" (types truncated).

mataslib commented 2 years ago

Make this vscode feature please - it's annoying to configure manually.

vensauro commented 1 year ago

one solution (that are not fast on the project that i works, because needs to load a bunch of things, but works very well) is the extension ts type expand.

https://github.com/d-kimuson/ts-type-expand

JohnGemstone commented 1 year ago

Thanks again for the hack!

I just wanted to call out that if your VSCode config specifies the "typescript.tsdk" option, you'll need to update the tsserver.ts in whatever location that option specifies. It would have saved me a bit of debugging time 🙃

Thank you!

SpencerKaiser commented 1 year ago

A little more context that I think is worth sharing... setting noErrorTruncation to true can cause some significant performance implications with errors.

I just spent 20 minutes trying to figure out why an error was popping up in my console but not inline where the error was... went over to GitHub to comment on a few things and let it sit and the error finally popped up and it clicked 🙃

I'm definitely keeping it set to true for usability but now have to remember that it can cause debugging issues with really complicated types ☹️

DanKaplanSES commented 1 year ago

I just wanted to call out that if your VSCode config specifies the "typescript.tsdk" option, you'll need to update the tsserver.ts in whatever location that option specifies. It would have saved me a bit of debugging time 🙃

Thank you for saying this because you saved me a lot of time! Slight correction, though: it's named tsserver.js


If for nothing else, I thought this was worth reporting for the irony: in my case, the ... was truncating a three character number.


@vensauro That extension doesn't seem to work anymore. Shame, because it looks really useful.

nikelborm commented 1 year ago

There is one awesome extension that is just enormously cool. It allows to explore "compiled" versions of very complex types

It allows to explore not only types and interfaces, but literally anything: vars, functions, classes, promises, generics

Name: TypeScript Explorer Id: mxsdev.typescript-explorer Description: Full type information for variables, components, functions, and more in TypeScript projects! Version: 0.4.0 Publisher: mxs VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=mxsdev.typescript-explorer

Screenshot from 2023-04-23 01-08-07

function UsePromiseAllMappedTrace<
  TInputArrayElement,
  TReturnArrayElement,
>(
  arrayToMap: TInputArrayElement[],
  elementGetter: (
    currentTraceNode: IPublicActionTraceNode,
    arrayElement: TInputArrayElement,
    index: number,
  ) => Promise<TReturnArrayElement>,
): (parentTraceNode: IPublicActionTraceNode) => Promise<TReturnArrayElement[]> {}
Zetxus commented 1 year ago

Thanks for the hack @Hati-, Another gotcha I found is that if you're using VSCode on the WSL2, your tsserver.js is located here:

~/.vscode-server/bin/*SOME_HASH_HERE*/extensions/node_modules/typescript/lib/tsserver.js

Here's a quick bash script I use to quickly switch back and forth to avoid any performance issues with high values on the truncation:

#!/bin/bash

if [ $# -lt 1 ]; then
  echo "Usage: $0 <directory_path> <new_length>?"
  exit 1
fi

directory_path="$1"
new_length="$2"

if [ -z "$2" ]
  then
    echo "No length supplied, will use default (160)"
    new_length=160
fi

file_path=$(find "$directory_path" -name "tsserver.js" 2>/dev/null)
if [ -z "$file_path" ]; then
  echo "tsserver.js file not found within directory $file_path after recursive search"
  exit 1
fi

echo "Found tsserver.js at \"$file_path\""

sed -i "s/var defaultMaximumTruncationLength = [0-9]\+;/var defaultMaximumTruncationLength = $new_length;/" "$file_path"

echo "Length updated successfully: "
cat $file_path | grep "defaultMaximumTruncationLength = "

Executing it with just the dir will result in resetting it to the default value of 160:

changeTypescriptHintLength.sh ~/.vscode-server

Executing it with a second argument will change it

changeTypescriptHintLength.sh ~/.vscode-server 800

Note: restarting the TS server is enough for the changes to take effect, no need to restart the entire VSCode.

blackhaj commented 1 year ago

This is awesome @Zetxus - thanks so much!

For me, the path name has spaces in it which was upsetting the sed command (I couldn't work out why), so with the help of chatGPT I managed to refactor it to use awk. Sharing here for others:

#!/bin/bash

if [ $# -lt 1 ]; then
  echo "Usage: $0 <directory_path> <new_length>?"
  exit 1
fi

directory_path="$1"
new_length="$2"

if [ -z "$2" ]
  then
    echo "No length supplied, will use default (160)"
    new_length=160
fi

file_path=$(find "$directory_path" -name "tsserver.js" 2>/dev/null)
if [ -z "$file_path" ]; then
  echo "tsserver.js file not found within directory $directory_path after recursive search"
  exit 1
fi

echo "Found tsserver.js at \"$file_path\""

# Use awk to perform the replacement
awk -v new_length="$new_length" '{sub(/var defaultMaximumTruncationLength = [0-9]+;/, "var defaultMaximumTruncationLength = " new_length ";")}1' "$file_path" > temp_file && mv temp_file "$file_path"

echo "Length updated successfully: "
cat "$file_path" | grep "defaultMaximumTruncationLength = "
Tatsh commented 1 year ago

This is awesome @Zetxus - thanks so much!

For me, the path name has spaces in it which was upsetting the sed command (I couldn't work out why), so with the help of chatGPT I managed to refactor it to use awk. Sharing here for others:

#!/bin/bash

if [ $# -lt 1 ]; then
  echo "Usage: $0 <directory_path> <new_length>?"
  exit 1
fi

directory_path="$1"
new_length="$2"

if [ -z "$2" ]
  then
    echo "No length supplied, will use default (160)"
    new_length=160
fi

file_path=$(find "$directory_path" -name "tsserver.js" 2>/dev/null)
if [ -z "$file_path" ]; then
  echo "tsserver.js file not found within directory $directory_path after recursive search"
  exit 1
fi

echo "Found tsserver.js at \"$file_path\""

# Use awk to perform the replacement
awk -v new_length="$new_length" '{sub(/var defaultMaximumTruncationLength = [0-9]+;/, "var defaultMaximumTruncationLength = " new_length ";")}1' "$file_path" > temp_file && mv temp_file "$file_path"

echo "Length updated successfully: "
cat "$file_path" | grep "defaultMaximumTruncationLength = "

Minor thing on the last line: grep "defaultMaximumTruncationLength = " "$file_path" will also work.

Djones4822 commented 1 year ago

Just to point out, I made this change on my windows install of VS code, I set defaultMaximumTruncationLength=800 and it seem that the change was reverted recently.

What I don't understand is why typeToString is not respecting the noErrorTruncation compiler option.

  function typeToString(type, enclosingDeclaration, flags = 1048576 /* AllowUniqueESSymbolType */ | 16384 /* UseAliasDefinedOutsideCurrentScope */, writer = createTextWriter("")) {
    const noTruncation = compilerOptions.noErrorTruncation || flags & 1 /* NoTruncation */;
    const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | 70221824 /* IgnoreErrors */ | (noTruncation ? 1 /* NoTruncation */ : 0));
    if (typeNode === void 0)
      return Debug.fail("should always get typenode");
    const printer = type !== unresolvedType ? createPrinterWithRemoveComments() : createPrinterWithDefaults();
    const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration);
    printer.writeNode(
      4 /* Unspecified */,
      typeNode,
      /*sourceFile*/
      sourceFile,
      writer
    );
    const result = writer.getText();
    const maxLength2 = noTruncation ? noTruncationMaximumTruncationLength * 2 : defaultMaximumTruncationLength * 2;
    if (maxLength2 && result && result.length >= maxLength2) {
      return result.substr(0, maxLength2 - "...".length) + "...";
    }
    return result;
  }

something about const noTruncation = compilerOptions.noErrorTruncation || flags & 1 /* NoTruncation */; is causing it to get ignored

noTruncationMaximumTruncationLength is set to 1e6 so this should not be an issue. I have to assume that when vscode is calling the typeToString function, the flag value is causing the compiler option to be ignored.

devcaeg commented 4 months ago

It seems that in recent versions the "defaultMaximumTruncationLength" option is no longer present in the "tsserver.js" file.

Where is this option currently available, or where can I increase this value?

dbersan commented 3 months ago

There is one awesome extension that is just enormously cool. It allows to explore "compiled" versions of very complex types

It allows to explore not only types and interfaces, but literally anything: vars, functions, classes, promises, generics

Name: TypeScript Explorer Id: mxsdev.typescript-explorer Description: Full type information for variables, components, functions, and more in TypeScript projects! Version: 0.4.0 Publisher: mxs VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=mxsdev.typescript-explorer

Screenshot from 2023-04-23 01-08-07

function UsePromiseAllMappedTrace<
  TInputArrayElement,
  TReturnArrayElement,
>(
  arrayToMap: TInputArrayElement[],
  elementGetter: (
    currentTraceNode: IPublicActionTraceNode,
    arrayElement: TInputArrayElement,
    index: number,
  ) => Promise<TReturnArrayElement>,
): (parentTraceNode: IPublicActionTraceNode) => Promise<TReturnArrayElement[]> {}

This extension simply doesn't solve the issue. You still need to manually click through this overly complex search tree. I just wanna see the full type, as plain string

MilesWellsSVT commented 3 months ago

It seems that in recent versions the "defaultMaximumTruncationLength" option is no longer present in the "tsserver.js" file.

Where is this option currently available, or where can I increase this value?

Same directory, but now in typescript.js

aasmal97 commented 3 months ago

Also for anyone interested, until we have an inbuilt fix/alternative, I did find another extension you can use on vscode that expands the entire (or set length and depth) of the type when you hover over it (similar to vscode hover functionality)

This is the extension: https://marketplace.visualstudio.com/items?itemName=MylesMurphy.prettify-ts

I went this route since currently,

  1. auto-updates to vscode
  2. re-installing packages

will occasionally reset the defaultMaximunTruncationLength values in these .js files, which will require you to manually update them again.

Also the most recent version of vscode's appears to sometimes ignore these values, even when set (even after reloading/restarting the server). At least that's what I was experiencing. Using this extension resolved things for me though