As we covered a 3 years back (gosh, the channel is old), if the result of a base class is the current class, a
TypeVar should be used as the annotation:
from typing import TypeVar U = TypeVar('U', bound='BaseUser') class BaseUser: @classmethod def new(cls: type[U]) -> U: ... def copy(self: U) -> U: ...
That's quite verbose, but it's how it should be done for the return type for inherited classes to be correct.
PEP 673 (landed in Python 3.11) introduced a new type
Self that can be used as a shortcut for exactly such cases:
from typing import Self class BaseUser: @classmethod def new(cls) -> Self: ... def copy(self) -> Self: ...