// MyVisitor.ts
abstract class AbstractLangVisitor<T> extends AbstractParseTreeVisitor<T> implements LangVisitor<T> {};
interface AbstractLangVisitor<T> extends LangVisitor<T> {};
class MyVisitor extends AbstractLangVisitor<string> {
// error ts(2425): Class 'AbstractLangVisitor<string>' defines instance member property 'visitFoo',
// but extended class 'MyVisitor' defines it as instance member function.
visitFoo(ctx: FooContext): string {
return 'foo';
}
}
However, if we generate the member differently so that it looks like a method rather than like a property...
// generated/LangVisitor.ts
...
visitFoo?(ctx: FooContext): Result;
...
// MyVisitor.ts
abstract class AbstractLangVisitor<T> extends AbstractParseTreeVisitor<T> implements LangVisitor<T> {};
interface AbstractLangVisitor<T> extends LangVisitor<T> {};
class MyVisitor extends AbstractLangVisitor<string> {
// ok! We can even use the new override annotation if we want!
override visitFoo(ctx: FooContext): string {
return 'foo';
}
}
Importantly, this alternative form still works if you declare it as a property rather than a method.
As far as I can tell this shouldn't break any existing code. However, I'm also not familiar with the precise semantics of matching members with interface definitions, so It's possible that there is some edge case where this fails that I haven't thought of.
Also, if someone actually prefers the old style of autocomplete, this could be slightly more annoying for them.
What does it do?
Generate
visitX?(ctx: XContext): Result
syntax rather thanvisitX?: (ctx: XContext) => Result
for generated listener and visitor interface members.Why would we want this?
Usually, method-style implementations work fine on implementing classes even when the method is declared as a property in the interface.
However, in some edge cases, it does not work so cleanly. Consider this construct in which
AbstractParseTreeVisitor
andLangVisitor
are combined intoAbstractLangVisitor
(see https://github.com/microsoft/TypeScript/issues/22815#issuecomment-375766197 for context on the shenanigans going on here)However, if we generate the member differently so that it looks like a method rather than like a property...
Importantly, this alternative form still works if you declare it as a property rather than a method.
One other small benefit...
This alternative form also gives better autocomplete when you ask the editor to generate a stub.
Drawbacks
As far as I can tell this shouldn't break any existing code. However, I'm also not familiar with the precise semantics of matching members with interface definitions, so It's possible that there is some edge case where this fails that I haven't thought of.
Also, if someone actually prefers the old style of autocomplete, this could be slightly more annoying for them.