TypeScript Version: 3.4.0-dev.20190329
Search Terms:
async, newline
Code
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
class
Foo {
constructor(private foo) {
console.log(`Creating Foo ${this.foo}...`);
}
static // a newline after 'static' is okay.
create() {
return new Foo('static');
}
async // a newline after 'async' makes `createAsync()` a normal function.
createAsync() {
return new Foo('async');
}
}
Foo.create().createAsync().then(x => console.log(x)); // createAsync() does not return a promise.
Expected behavior:
If there is a newline between the async keyword and the function identifier, I expect the function to be an asynchronous function. A newline, for example, is allowed between the static keyword and the function identifier.
Actual behavior:
The function is not an asynchronous function and tsc returns the following error:
error TS2339: Property 'then' does not exist on type 'Foo'.
Playground Link:
https://www.typescriptlang.org/play/index.html#src=class%0D%0AFoo%20%7B%0D%0A%20%20%20%20constructor(private%20foo)%20%7B%0D%0A%20%20%20%20%20%20%20%20console.log(%60Creating%20Foo%20%24%7Bthis.foo%7D...%60)%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20static%20%2F%2F%20a%20newline%20after%20'static'%20is%20okay.%0D%0A%20%20%20%20%20%20%20%20create()%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20new%20Foo('static')%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20async%20%2F%2F%20a%20newline%20after%20'async'%20makes%20%60createAsync()%60%20a%20normal%20function.%0D%0A%20%20%20%20createAsync()%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20new%20Foo('async')%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0AFoo.create().createAsync().then(x%20%3D%3E%20console.log(x))%3B
Related Issues:
I think typescript is correct. Running the js version of your code in node:
class Foo {
constructor(foo) {
this.foo = foo;
console.log(`Creating Foo ${this.foo}...`);
}
static // a newline after 'static' is okay.
create() {
return new Foo('static');
}
async // a newline after 'async' makes `createAsync()` a normal function.
createAsync() {
return new Foo('async');
}
}
Foo.create().createAsync().then(x => console.log(x));
results in:
Z:\tmp\ts\index.js:11
createAsync() {
^^^^^^^^^^^
SyntaxError: Unexpected identifier
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:617:28)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
at Function.Module.runMain (module.js:694:10)
at startup (bootstrap_node.js:204:16)
at bootstrap_node.js:625:3
@DanielRosenwasser maybe typescript should report a better error in this case?
async is NOT a keyword, itself is a valid identifier. By separating them you're declaring a class field named async.
@trotyl That's also why TypeScript reports an error if you have noImplicitAny enabled (which I think you should).
https://typescript-play.js.org/#code/MYGwhgzhBQBiD28AEBvaSNOPAdhALgE4Cuw+8hAFAA6ECWAbmPgKZIBmiAlKupv9jzwQLAHQh4Ac0oADAMKEWzOjklIEyACQp8ACzoRRneAF9R5mVwDcfDCei2kBZcCQB6N0jBIcLAO4gKmxg7KyESADkzvh0wBFIBkjwANZgAJ6ijgKKzCyUPGj8-Ir4xIQ4Pv7qiJRR+C4R1o72jpBpOK4eXpUBQV6hLOERbR3xALZgySwQSDLAOawAghDtwPky3TgUEyAcxB0xuJnZSksrHfm8RZglZRW+ftXwtSNxTfz29kA
Not to pile on, but the grammar for an AsyncMethod in the ECMAScript spec is basically
AsyncMethod [no LineTerminator here] PropertyName
(UniqueFormalParameters){
AsyncFunctionBody
}
maybe typescript should report a better error in this case?
I don't know what error we can give except for in noImplicitAny, which isn't a bad idea. Feel free to open a PR!
I don't see why TypeScript should raise any error, as this is legal code. Besides noImplicitAny (which is unrelated) this sounds like a case for a linter rule.
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
Most helpful comment
asyncis NOT a keyword, itself is a valid identifier. By separating them you're declaring a class field namedasync.