Typescript: Detect uninitialized readonly variables

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.

1 Like

Hi @m-gallesio,

Thanks for bringing this up!

Indeed it is an interesting case. I’m a bit surprised TypeScript doesn’t pick it up when extending the class concretely. This does look like something we could detect.

I raised an internal insight so that we consider this when tackling a sprint on related topics.
Let me know if you are aware of other variations of this problem that we could consider.

I’ll let other people comment too if they have stumbled upon this issue or have other thoughts.

1 Like