Modeling partial initialization in the type system

This problem has been raised multiple times; one of the proposed solution is TypeAssert, which supposedly works something like this:

class HasIntegralP(Protocol):
    p: int

class Brittle:
    p: int | None

    def late_initializer(self) -> TypeAssert[HasIntegralP]: ...
    def run(self: Brittle & HasIntegralP) -> None: ...
brittle = Brittle()         # brittle.p: int | None
brittle.late_initializer()  # brittle.p: int
brittle.run()               # fine
brittle = Brittle()         # brittle.p: int | None
brittle.run()               # error: Brittle is not compatible with HasIntegralP

The corresponding code in TypeScript:

type HasNumericP = { p: number };

class Brittle {
    constructor(public p: number | null) {}

    lateInitializer(): asserts this is HasNumericP {}
    run(this: Brittle & HasNumericP) {}
}
const brittle: Brittle = new Brittle(0);
brittle.lateInitializer();
brittle.run();                            // fine
const brittle: Brittle = new Brittle(0);
brittle.run();                            // error: Type 'Brittle' is not assignable to type 'HasNumericP'.

I can’t find the actual discussion anywhere, but there are multiple references around this forum:

2 Likes