-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
Bug Report
π Search Terms
parameter decorator async await context syntax error
π Version & Regression Information
- This is the behavior in every version I tried
β― Playground Link
Playground link with relevant code
π» Code
function decorator(a: any): any {}
function fn(value: Promise<number>): any {
class Class {
async method(@decorator(await value) arg: number) {}
}
return Class
}
π Actual behavior
The above sample code is compiled without any errors by TypeScript and generates the following invalid JavaScript code, which contains a syntax error:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
function decorator(a) { }
function fn(value) {
class Class {
async method(arg) { }
}
__decorate([
__param(0, decorator(await value))
], Class.prototype, "method", null);
return Class;
}
The specific syntax error is that await
is used outside of an async
function. I originally discovered this issue with the following incorrect code:
function decorator(a: any): any {}
function fn(value: Promise<number>): any {
class Class {
method(@decorator(await value) arg: number) {}
}
return Class
}
That is correctly detected as an error by TypeScript, but it has the wrong suggestion:
example.ts:4:23 - error TS1308: 'await' expressions are only allowed within async functions and at the top levels of modules.
4 method(@decorator(await value) arg: number) {}
~~~~~
example.ts:4:5
4 method(@decorator(await value) arg: number) {}
~~~~~~
Did you mean to mark this function as 'async'?
Found 1 error in example.ts:4
The async
should be added to the outer function, not to the inner method.
π Expected behavior
Both the error message suggestion and the compiler's validation logic itself are incorrect about the async/await context of parameter decorators. It should be the context of the class, not the context of the method, because the generated decorator code is inserted as sibling statements of the class. In other words adding async
on the outer function like this should be the only valid way to fix this code:
function decorator(a: any): any {}
async function fn(value: Promise<number>): any {
class Class {
method(@decorator(await value) arg: number) {}
}
return Class
}
The additional context here is that I'm the developer behind esbuild and I'm trying to reverse-engineer how I should be converting TypeScript code to JavaScript code. A user sent me an issue with a similar problem in esbuild: evanw/esbuild#2147. When investigating that bug I discovered this bug in TypeScript and reported it here.