Search code examples
pythontype-hintingmypy

How to set class property as class method return type?


I got a class A who has a class method and take it's class property as return type.

And a got a class B who inherit from class A.

How to set get_instance return type in A and to inform B get the right type?

# typings.py
from typing import TypeVar, Type

AType = TypeVar("AType", bound="A")

T = TypeVar("T", int, str)


class A:
    TYPE = int

    @classmethod
    def get_instance(cls: Type[AType]) -> "AType.TYPE":
        return cls.TYPE()


class B(A):
    TYPE = str


a = B.get_instance()

reveal_type(a)

mypy typings.py

typings.py:12: error: Name "AType.TYPE" is not defined
typings.py:17: error: Incompatible types in assignment (expression has type "Type[str]", base class "A" defined the type as "Type[int]")
typings.py:22: note: Revealed type is "Any"

Solution

  • Parameterise over the TYPE by making the class Generic. This allows to refer to the class attribute TYPE and the return type with the same type variable:

    from typing import TypeVar, Type, Generic
    
    T = TypeVar("T", str, int)
    
    
    class Base(Generic[T]):
        TYPE: Type[T]
    
        @classmethod
        def get_instance(cls: "Type[Base[T]]") -> "T":
            return cls.TYPE()
    

    Note that this prevents setting TYPE directly. A separate generic Base and concrete A definition is needed.

    class A(Base[int]):
        TYPE = int
    
    class B(Base[str]):
        TYPE = str