tunnelvisionlabs / antlr4ts

Optimized TypeScript target for ANTLR 4

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Property 'xxx' has no initializer and is not definitely assigned in the constructor.

mike-lischke opened this issue · comments

When "strictPropertyInitialization" is not specified or set to true then rules with a label will generate code that produces an error with Typescript. This rule:

routineOption:
    option = COMMENT_SYMBOL textLiteral
    | option = LANGUAGE_SYMBOL SQL_SYMBOL
    | option = NO_SYMBOL SQL_SYMBOL
    | option = CONTAINS_SYMBOL SQL_SYMBOL
    | option = READS_SYMBOL SQL_SYMBOL DATA_SYMBOL
    | option = MODIFIES_SYMBOL SQL_SYMBOL DATA_SYMBOL
    | option = SQL_SYMBOL SECURITY_SYMBOL security = (
        DEFINER_SYMBOL
        | INVOKER_SYMBOL
    )
;

contains 2 labels (option and security) and generates this code:

export class RoutineOptionContext extends ParserRuleContext {
	public _option: Token;
	public _security: Token;
	public textLiteral(): TextLiteralContext | undefined {
		return this.tryGetRuleContext(0, TextLiteralContext);
	}
...
}

And because neither of _option and _security are initialized, this produces the error mentioned in the title.

A workaround is to set "strictPropertyInitialization" in tsconfig.json to false, but I would prefer that antlr4ts makes these class members optional, like:

export class RoutineOptionContext extends ParserRuleContext {
	public _option: Token | undefined;
	public _security: Token | undefined;
	public textLiteral(): TextLiteralContext | undefined {
		return this.tryGetRuleContext(0, TextLiteralContext);
	}
...
}

Side note: the choice to prefix all such label variables with an underscore is, at least, questionable. They are not private and the convention is that only private variables are written that way (actually, I never use an underscore in my fields/variables).

I encountered this problem as well. We use "strict: true" option in tsconfig.json in our project.

I considered various workarounds and at the end decided to:

  • leave "strict: true" option as is;
  • not to version-control generated parser and hand-edit it;
  • rather patch the parser with replace-in-file utility.

... but I would prefer that antlr4ts makes these class members optional ...

This is definitely not a fix. Significant effort (e.g. antlr/antlr4#1576, antlr/antlr4#1582) went into ensuring that non-optional properties in the rule were generated as non-optional properties in the grammar. For the example above, _option is only undefined as a non-observable transient state. When routineOption() returns without an error, _option will be a valid Token.

Is there another way to suppress this warning for members that will be initialized before the type is used, but are not initialized in the constructor?

Looks like we can add a definite assignment assertion to the property:

public _option!: Token;

But the properties are not always assigned! For instance security is only used in specific alts. In all others it is unassigned and should appear therefore as optional.

In all others it is unassigned and should appear therefore as optional.

Yes, these should appear as optional.

Unfortunately, it looks like the TokenDecl and RuleContextDecl models don't currently track an optional property the same way context getters do. The temporary solution is declaring all context properties with a non-null assertion operator, which adheres to the C# Nullable Reference Types practice of treating "oblivious" (or unknown nullability) scenarios as non-null.