-
Notifications
You must be signed in to change notification settings - Fork 2k
use Symbol.hasInstance for looser instanceof checks #989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
*/ | ||
|
||
// eslint-disable-next-line flowtype/no-weak-types | ||
export default function attachHasInstanceSymbol(ctor: Function): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure what a better type here would be maybe GraphQLType?
any thoughts? I realize its a sort of silly change but it could potentially solve a bunch of annoying npm/yarn induced issues we see a lot on Gatsby |
Why does this have to be "attached"? class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true seems more natural to me to define it on the class |
Just to add my vote to this — I hear someone complaining about Gatsby being broken due to the overly strict check every few days now. |
}, | ||
}); | ||
|
||
ctor.prototype[Symbol.for(tag)] = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why Symbol.for()
and not Symbol()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one fetches a global symbol by name vs creating a new symbol:
Symbol('foo') == Symbol('foo') // false
Symbol.for('foo') == Symbol.for('foo') // true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand, but why is that desirable here? Imo the symbol should be private or if it's public, it should be exported, no retrievable for everyone through a magic string. You just need to save the symbol in a variable and reuse it. Otherwise you might as well just use a regular property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its not using a symbol for privacy, it's to avoid muddying up people's namespace on the class for things they can use as property names. With the symbol you don't have to worry (nearly as much) about accidentally overwriting the tag in an instance when you just wanted to define an unrelated property. Incidentally this approach is how React tags elements as "ReactElements"
This PR is important.
This has impacted the reactjs.org repo twice now, most recently with reactjs/react.dev/pull/222. Each time it's cost me time and confusion to debug because the behavior is unexpected and confusing. |
I'm going to close this PR since it doesn't solve the issue at hand, but instead moves it and creates new problems. See my comments in #996 for why this issue is more challenging than this PR's solution. I would much prefer an approach which first improves the API by introducing predicate functions instead of relying on I'd be more than happy to review PRs which tackled improving these errors |
Hmm I don't think I understand the advantage to the predicate function of approach. isn't it essentially going to be the same logic except instead of instanceof checking a class tag, you have a function doing it? I'm not sure otherwise how'd you structure such functions other than doing a bunch of ugly tests for internal properties on the class instances, that hardly seems cleaner than leveraging language features designed for this case? In any case I probably won't work on a follow-up PR, 4 months of no feedback makes it feel like it'd be a waste of time :/. Thanks again. |
fixes #491
I'm not entirely sure how to field test this but
Symbol.for
should be resilent over package boundaries since its all the same runtime.