TypeScript allows declaring a readonly
uninitialized field, but does not check whether it gets initialized in the constructor which is the only place it could be:
export class A {
readonly field1: number;
readonly field2: number; // not initialized in the constructor => always undefined
constructor(field: number) {
this.field1 = field;
}
}
We make extensive use of abstract classes / the Template method pattern, and we had the following happen several times:
export abstract class A {
protected abstract readonly propertyName: string;
someMethod() {
doSomethingWith(this.propertyName);
}
}
export class Wrong extends A {
protected override readonly propertyName: "anActualName"; // this LOOKS like it sets the variable but it does NOT
}
export class Right extends A {
protected override readonly propertyName = "anActualName"; // this is what the abstract class actually expects
}
Constant literals are allowed as types, so the code looks right at a cursory glance and compiles without errors, but it causes a bug at runtime due to the undefined
value.
This might also apply to other languages.