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: