Summary
In stub files, setter return types must be explicitly annotated and should match the getter’s return type. Using -> None on the setter without a corresponding getter annotation leads to type‑checking errors in IDEs like PyCharm.
Root Cause
- The stub type checker infers the property’s type from the getter’s return annotation.
- When the stub defines a setter that returns
Nonebut the getter is typed asint, the checker expects the setter’s return type to be compatible withint. - Annotating the setter as
-> Nonealone does not satisfy the inferredinttype, causing a mismatch error.
Why This Happens in Real Systems
- Python descriptors expose a separate getter and setter; static analysers treat the property’s type as the getter’s return type.
- Stub files are intended for IDE assistance and type checking, not for full implementation.
- If a stub does not mirror the concrete implementation’s signature, type mismatches appear, even though the runtime behavior is correct.
Real-World Impact
- False positive warnings interrupt development flow in IDEs.
- Developers may suppress errors with comments instead of fixing the stub, leading to inconsistent documentation.
- Misleading type hints can propagate to other modules, creating subtle runtime bugs.
- Delayed feedback slows down refactoring and code reviews.
Example or Code
class test:
_foo: int
def __init__(self) -> None: ...
@property
def foo(self) -> int: ...
@foo.setter
def foo(self, bar: int) -> None: ...
How Senior Engineers Fix It
- Annotate the getter with the most specific type and annotate the setter with
-> Noneonly if that matches the expected type. - Synchronize both annotations: if the getter returns
int, the setter can returnNonebut must not be typed as-> int. - Use a union or overload only when the setter legitimately may return something other than
None.
Why Juniors Miss It
- Junior developers often focus on runtime correctness and ignore the IDE’s static expectations.
- They may copy the getter’s signature into the setter without understanding the type‑checking model.
- Without awareness of descriptor protocol nuances, they apply work‑arounds like
int | Nonethat are not idiomatic for stubs.