X Tutup
The Wayback Machine - https://web.archive.org/web/20251209153150/https://github.com/microsoft/TypeScript/pull/44936
Skip to content

Conversation

@amcasey
Copy link
Member

@amcasey amcasey commented Jul 8, 2021

When a class declaration lacks a name, don't throw an exception when
producing the display parts (e.g. for QuickInfo).

Remaining issues:

  1. The name shows as "__missing", the name of the underlying symbol,
    rather than "(Missing)", as it is for the corresponding function
    declaration case (because the parse constructs a missing identifier
    node for the function declaration).
  2. "(Missing)" is hard-coded, rather than being a localizable resource
    string.
  3. When an anonymous class declaration is a default export, the
    corresponding symbol is named "default", resulting in the confusing
    display string "class default".

Since display parts are built using existing symbolToString
functionality, it wasn't clear whether detecting special symbol names
and replacing them with user-friendly strings could be done without
breaking other functionality.

Similarly, changing the shape of the parse tree seemed riskier than the
problem justified (the user experience is just not getting QuickInfo for
the incomplete declaration, which seems acceptable).

When a class declaration lacks a name, don't throw an exception when
producing the display parts (e.g. for QuickInfo).

Remaining issues:
 1. The name shows as "__missing", the name of the underlying symbol,
    rather than "(Missing)", as it is for the corresponding function
    declaration case (because the parse constructs a missing identifier
    node for the function declaration).
 2. "(Missing)" is hard-coded, rather than being a localizable resource
    string.
 3. When an anonymous class declaration is a default export, the
    corresponding symbol is named "default", resulting in the confusing
    display string "class default".

Since display parts are built using existing `symbolToString`
functionality, it wasn't clear whether detecting special symbol names
and replacing them with user-friendly strings could be done without
breaking other functionality.

Similarly, changing the shape of the parse tree seemed riskier than the
problem justified (the user experience is just not getting QuickInfo for
the incomplete declaration, which seems acceptable).
@amcasey amcasey requested a review from sandersn July 8, 2021 00:16
@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Jul 8, 2021
@amcasey
Copy link
Member Author

amcasey commented Jul 8, 2021

Stack was

Cannot read property 'length' of undefined
TypeError: Cannot read property 'length' of undefined
    at Object.find (e:\ts_gh\src\compiler\core.ts:217:35)
    at getAdjustedLocationForClass (e:\ts_gh\src\services\utilities.ts:761:37)
    at getAdjustedLocationForDeclaration (e:\ts_gh\src\services\utilities.ts:814:28)
    at getAdjustedLocation (e:\ts_gh\src\services\utilities.ts:923:30)
    at getAdjustedReferenceLocation (e:\ts_gh\src\services\utilities.ts:1095:16)
    at Object.getMeaningFromLocation (e:\ts_gh\src\services\utilities.ts:91:16)
    at Object.getSymbolDisplayPartsDocumentationAndSymbolKind (e:\ts_gh\src\services\symbolDisplay.ts:147:43)
    at e:\ts_gh\src\services\services.ts:1653:31
    at Object.runWithCancellationToken (e:\ts_gh\src\compiler\checker.ts:704:28)
    at Proxy.getQuickInfoAtPosition (e:\ts_gh\src\services\services.ts:1652:83)
    at IOSession.Session.getQuickInfoWorker (e:\ts_gh\src\server\session.ts:1725:60)
    at Session.handlers.ts.Map.ts.getEntries._a.<computed> (e:\ts_gh\src\server\session.ts:2718:51)
    at e:\ts_gh\src\server\session.ts:3018:69
    at IOSession.Session.executeWithRequestId (e:\ts_gh\src\server\session.ts:3008:24)
    at IOSession.Session.executeCommand (e:\ts_gh\src\server\session.ts:3018:29)
    at IOSession.Session.onMessage (e:\ts_gh\src\server\session.ts:3050:61)
    at Interface.<anonymous> (e:\ts_gh\src\tsserver\nodeServer.ts:753:26)
    at Interface.emit (events.js:315:20)
    at Interface._onLine (readline.js:337:10)
    at Interface._normalWrite (readline.js:482:12)
    at Socket.ondata (readline.js:194:10)
    at Socket.emit (events.js:315:20)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at Socket.Readable.push (internal/streams/readable.js:223:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)

},
"displayParts": [
{
"text": "class",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class default is weird but correct, at least according to commonjs:

  1. assignment to a variable gives an anonymous function the name of the variable, eg var f = function () { }
  2. JS classes are just functions.
  3. export default x translates to exports.default = x in commonjs.

I think this is in the standard, but at least node and TS agree on this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node appears to agree even in ESM mode:

foo.mjs

export default class {}

bar.mjs

import foo from './foo.mjs';
console.log(foo);

> node bar.mjs

[class default]

// for class and function declarations, use the `default` modifier
// when the declaration is unnamed.
const defaultModifier = find(node.modifiers!, isDefaultModifier);
const defaultModifier = node.modifiers && find(node.modifiers, isDefaultModifier);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also do

Suggested change
const defaultModifier = node.modifiers && find(node.modifiers, isDefaultModifier);
const defaultModifier = forEach(node.modifiers, isDefaultModifier);

or

Suggested change
const defaultModifier = node.modifiers && find(node.modifiers, isDefaultModifier);
const defaultModifier = node.modifiers?.find(isDefaultModifier);

@DanielRosenwasser DanielRosenwasser merged commit 792e6d6 into microsoft:main Aug 6, 2021
@amcasey amcasey deleted the IncompleteClassParts branch August 9, 2021 16:14
BobobUnicorn pushed a commit to BobobUnicorn/TypeScript that referenced this pull request Oct 24, 2021
…t#44936)

When a class declaration lacks a name, don't throw an exception when
producing the display parts (e.g. for QuickInfo).

Remaining issues:
 1. The name shows as "__missing", the name of the underlying symbol,
    rather than "(Missing)", as it is for the corresponding function
    declaration case (because the parse constructs a missing identifier
    node for the function declaration).
 2. "(Missing)" is hard-coded, rather than being a localizable resource
    string.
 3. When an anonymous class declaration is a default export, the
    corresponding symbol is named "default", resulting in the confusing
    display string "class default".

Since display parts are built using existing `symbolToString`
functionality, it wasn't clear whether detecting special symbol names
and replacing them with user-friendly strings could be done without
breaking other functionality.

Similarly, changing the shape of the parse tree seemed riskier than the
problem justified (the user experience is just not getting QuickInfo for
the incomplete declaration, which seems acceptable).
@microsoft microsoft locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants

X Tutup