Skip to content

allow unused private well-known symbol members#42104

Closed
Zzzen wants to merge 3 commits intomicrosoft:mainfrom
Zzzen:mark-itertors-symbols-as-used
Closed

allow unused private well-known symbol members#42104
Zzzen wants to merge 3 commits intomicrosoft:mainfrom
Zzzen:mark-itertors-symbols-as-used

Conversation

@Zzzen
Copy link
Copy Markdown
Contributor

@Zzzen Zzzen commented Dec 24, 2020

Fixes #42051

Comment on lines +33 to +38
private async *[Symbol.asyncIterator]() {}
~~~~~~~~~~~~~~~~~~~~~~
!!! error TS6133: '[Symbol.asyncIterator]' is declared but its value is never read.
private *[Symbol.iterator]() {}
~~~~~~~~~~~~~~~~~
!!! error TS6133: '[Symbol.iterator]' is declared but its value is never read.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It’s a little confusing to consider what it means for these members to be marked as private, but let’s think about the consequences:

  1. Within the program, consumers can spread or for/of an instance of Unused with no problems, but they can’t directly access this member via element access.
  2. Outside the program (i.e., consumers of the declaration emit as a library) can spread or for/of an instance of Unused, but they don’t know what type it yields. (The member declaration is preserved, but the type annotation is erased.)

I think because these members are to some degree usable by external consumers, we can’t ever mark them unused (at least, not if the class is exported or globally accessible).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

  1. Outside the program (i.e., consumers of the declaration emit as a library) can spread or for/of an instance of Unused, but they don’t know what type it yields. (The member declaration is preserved, but the type annotation is erased.)

🤔 Shouldn't symbol members behave like ordinary members? I don't know why not all following accesses report errors? Playground

class UsedOutsideClass {
    private *[Symbol.iterator](){ return ''; }
    private ['bar'] = () => {}
    private baz = () => {}
}

const foo = new UsedOutsideClass();
// No error ❓
foo[Symbol.iterator]()
// No error ❓
foo['bar']()
// Error ✅
foo.baz()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Uhhh, that looks like a separate bug to me 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The salient thing here isn’t the member declaration, it’s the access. foo.bar is an error but foo['bar'] is not. Anyway, don’t worry about that for this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

😕 So we should simply ignore private Symbol.iterator/Symbol.asyncIterator when checking unused members?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, at least when the class is global or exported.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It occurs to me that maybe all well-known symbols should be ignored because they are designed to work implicitly and we have no practical way to track the usages.

class Foo {
  // Error: '[Symbol.toPrimitive]' is declared but its value is never read.
  private [Symbol.toPrimitive]() {
    return 1;
  }

  test() {
    // Logs 1
    console.log(String(this))
  }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That seems plausible to me.

@Zzzen Zzzen force-pushed the mark-itertors-symbols-as-used branch from cc699ba to ef0a755 Compare April 23, 2021 16:32
@Zzzen Zzzen changed the title mark [Symbol.asyncIterator] and [Symbol.iterator] methods as used in iterations allow unused private well-known symbol members Apr 23, 2021
@sandersn sandersn assigned andrewbranch and unassigned armanio123 Mar 16, 2022
andrewbranch
andrewbranch previously approved these changes Mar 16, 2022
Copy link
Copy Markdown
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

This seems good to me. I’d like one more person to weigh in. @rbuckton @weswigham?

@andrewbranch andrewbranch requested review from rbuckton and weswigham and removed request for elibarzilay March 17, 2022 22:59
isIdentifier(node.expression) &&
node.expression.escapedText === "Symbol"
)) {
return false;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't like this. We're able to do way better than syntactic specialization. Instead, check if the type of the name expression is the same as one of the members of the global SymbolConstructor interface.

export class C {
private *[iteratorSymbol]() {
~~~~~~~~~~~~~~~~
!!! error TS6133: '[iteratorSymbol]' is declared but its value is never read.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We probably should not error here, but It is gonna take a lot of effort to fix.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually, this should be easy to fix. Compare the type of the computer name, rather than the symbol. Every unique symbol has a unique type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm, definitely a bug - I've opened #53276 to track it, since all members of the global SymbolConstructor are, in fact, declared as unique symbols nowadays.

Copy link
Copy Markdown
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

I think this is close to the right approach, with the changes I suggested, but is blocked on #53276 being fixed. I'd prefer we didn't have anything special for well-known symbols that doesn't apply to unique symbols in general, but relaxing usage checks for them, since they specify language-level protocol implementations, even when private, is a reasonable exception to the rule. (Though I could be wrong about that - someone may be equally sad that their private [myProtocolSymbol] method is marked as unused; it's just less common)

@typescript-bot
Copy link
Copy Markdown
Collaborator

With 6.0 out as the final release vehicle for this codebase, we're closing all PRs that don't fit the merge criteria for post-6.0 patches. If you think this was a mistake and this PR fits the post-6.0 patch criteria, please post to the 6.0 iteration issue with details (specifically, which PR and which patch criteria it satisfies).

Next steps for PRs:

  • For crash bugfixes or language service improvements, PRs are currently accepted at the typescript-go repo
  • Changes to type system behavior should wait until after 7.0, at which point mainline TypeScript development will resume in this repository with the Go codebase
  • Library file updates (lib.d.ts etc) continue to live in this repo or the DOM Generator repo as appropriate

@github-project-automation github-project-automation bot moved this from Waiting on author to Done in PR Backlog Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Private [Symbol.asyncIterator] and [Symbol.iterator] methods incorrectly reported as unused

7 participants