-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Invalid transpiled/runtime code with the new disposable/using feature in 1.37.0+ release #20742
Comments
As you might have been able to deduce from the tags that Bartek set, Deno doesn't actually use TSC to transpile Typescript (they instead use SWC for performance). You can play around in the SWC playground to reproduce the bug. |
@lino-levan thanks for the pointer! The great news for anyone excited about leveraging Hopefully this makes it into the next Deno release as well. |
Here's another reproduction case: Source: function main() {
var _stack = "foo";
console.log(eval("_stack"));
using bar = null;
console.log(bar);
}
main(); Terminal:
Transpiled: function dispose_SuppressedError(suppressed1, error1) {
if (typeof SuppressedError1 !== "undefined") {
dispose_SuppressedError = SuppressedError1;
} else {
dispose_SuppressedError = function SuppressedError1(suppressed1, error1) {
this.suppressed = suppressed1;
this.error = error1;
this.stack = new Error().stack;
};
dispose_SuppressedError.prototype = Object.create(Error.prototype, {
constructor: {
value: dispose_SuppressedError,
writable: true,
configurable: true
}
});
}
return new dispose_SuppressedError(suppressed1, error1);
}
function _dispose(stack1, error1, hasError1) {
function next1() {
while(stack1.length > 0){
try {
var r1 = stack1.pop();
var p1 = r1.d.call(r1.v);
if (r1.a) return Promise.resolve(p1).then(next1, err1);
} catch (e1) {
return err1(e1);
}
}
if (hasError1) throw error1;
}
function err1(e1) {
error1 = hasError1 ? new dispose_SuppressedError(e1, error1) : e1;
hasError1 = true;
return next1();
}
return next1();
}
function _using(stack1, value1, isAwait1) {
if (value1 === null || value1 === void 0) return value1;
if (typeof value1 !== "object") {
throw new TypeError("using declarations can only be used with objects, null, or undefined.");
}
if (isAwait1) {
var dispose1 = value1[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")];
}
if (dispose1 === null || dispose1 === void 0) {
dispose1 = value1[Symbol.dispose || Symbol.for("Symbol.dispose")];
}
if (typeof dispose1 !== "function") {
throw new TypeError(`Property [Symbol.dispose] is not a function.`);
}
stack1.push({
v: value1,
d: dispose1,
a: isAwait1
});
return value1;
}
function main() {
try {
var _stack = [];
var _stack = "foo";
console.log(eval("_stack"));
var bar = _using(_stack, null);
console.log(bar);
} catch (_) {
var _error = _;
var _hasError = true;
} finally{
_dispose(_stack, _error, _hasError);
}
}
main(); The transpiled file reveals that the |
The original issue is now fixed, so closing. The |
As of the latest
1.37.1
release,deno
supports the new TypeScript 5.2 Explicit Resource Management feature.However, it transpiles into invalid code which will cause unexpected runtime errors. The strange thing is test-compiling the same code snippet using
tsc
directly will produce valid code.Here's a simple reproducer:
Saving that into a file named
using_bug.ts
and running it withdeno run using_bug.ts
will throw:As an attempt to reveal the transpiled JS code behind the scene, running
deno bundle ...
will produce:Which indeed explains that runtime error. (
bar
is gone andfoo
is renamed tofoo1
in the wrong scope.On the contrary,
tsc
version5.2.2
(which matches the TypeScript version ofdeno
1.37.1
exactly) will produce:Where
foo
andbar
are hoisted withvar
and does not share the same bug.In case it's helpful, here's the content of
tsconfig.json
when runningtsc
which produced the output above:The text was updated successfully, but these errors were encountered: