fix(interopDefault): skip bind for Symbol properties#441
Conversation
When accessing Symbol properties like Symbol.asyncDispose or Symbol.dispose through the interopDefault proxy, skip the Function.prototype.bind() call. Bound functions are rejected by V8 when used with native 'await using' / 'using' syntax (Node 24+), causing: TypeError: Symbol(Symbol.asyncDispose) is not a function Fixes #437
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe Proxy.get trap in interopDefault was changed: function values are no longer bound to the default export when the accessed property is ChangesSymbol Property Binding Fix
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| } else if (needsDefaultFallback) { | ||
| value = def[prop]; | ||
| if (typeof value === "function") { | ||
| if (typeof value === "function" && typeof prop !== "symbol") { |
There was a problem hiding this comment.
Wondering if this might a too generic surface. Error case is with well known reserved symbols.
Address review feedback - instead of skipping bind for all Symbol properties, only skip for well-known disposal symbols (Symbol.asyncDispose, Symbol.dispose) that V8 requires to be unbound for native 'await using' / 'using' syntax (Node 24+).
|
@pi0 Good point! I've narrowed the check to only target disposal symbols ( These are the specific symbols that V8 rejects when bound, due to the native Updated the fix: - if (typeof value === "function" && typeof prop !== "symbol") {
+ if (
+ typeof value === "function" &&
+ prop !== Symbol.asyncDispose &&
+ prop !== Symbol.dispose
+ ) { |
|
@pi0 Good question! The Symbol.dispose/asyncDispose check is actually quite specific:
The alternative would be to check if the prop is a Symbol type in general ( Would you prefer I add a more detailed comment explaining why these specific symbols need special handling? |
|
@pi0 Just following up on this PR. I've addressed your feedback by narrowing the check to only target disposal symbols ( Is there anything else you'd like me to adjust? Happy to make further changes if needed. |
|
@pi0 The change is already scoped to only the well-known reserved symbols:
These are the only symbols that V8 rejects when bound. Regular property symbols are not affected. |
|
why closed? |
|
Hi @pi0! Sorry about the confusion — the PR was closed automatically (possibly due to inactivity or branch cleanup). I'm reopening it now since the fix is still valid. The change only targets well-known disposal symbols ( and ) that V8 rejects when bound in Node 24+ with / syntax. Would you like me to reopen this PR or create a fresh one? |
|
yes please you can reopen |
Problem
interopDefaultinsrc/utils.tswraps fall-through methods withFunction.prototype.bindto preservethisfor the underlying default export. When the property accessed isSymbol.asyncDispose/Symbol.disposeand the consumer uses nativeawait using/using(Node 24+), V8 rejects the bound function returned through the proxygettrap with:This does not surface when the calling file is itself transpiled by jiti, because Babel rewrites
await usingto aDisposableStackhelper that calls the bound function directly.Fix
Skip
Function.prototype.bind()for Symbol properties in theinteropDefaultproxygettrap. Symbol properties likeSymbol.asyncDisposeandSymbol.disposeare protocol methods that should maintain their original reference identity.Testing
Tested with Node 24+ using the minimal reproduction from #437:
Fixes #437
Summary by CodeRabbit