Search code examples
pythonmypypython-typing

How to type an argument which will be subclassed in Python


I have a piece that follows such pattern

from typing import Any


class Base:
    ...


class Derived1(Base):
    ...


class Derived2(Base):
    ...


class BasicApp:
    # how to type d in this base class?
    def handle(self, d: Base) -> None:
        print("handle from BasicApp", d)


class AppX(BasicApp):
    def handle(self, d: Derived1) -> None:
        print("handle from AppX", d)


class AppY(BasicApp):
    def handle(self, d: Derived2) -> None:
        print("handle from AppY", d)

I'm not sure what's the right way to type d in BasicApp.d.

I tried d: Base, then

error: Argument 1 of "handle" is incompatible with supertype "BasicApp"; supertype defines the argument type as "Base"

I tried T = TypeVar('T', bound=Base) and d: T, then

error: Argument 1 of "handle" is incompatible with supertype "BasicApp"; supertype defines the argument type as "T"

What's the right way?


Solution

  • You need to make BaseApp generic, so that the argument type for the method is effectively a "function" of the class itself.

    from typing import Generic, TypeVar
    
    
    class Base:
        ...
    
    
    class Derived1(Base):
        ...
    
    
    class Derived2(Base):
        ...
    
    
    T = TypeVar("T", bound=Base)
    
    
    class BasicApp(Generic[T]):
        # how to type d in this base class?
        def handle(self, d: T) -> None:
            print("handle from BasicApp", d)
    
    
    class AppX(BasicApp[Derived1]):
        def handle(self, d: Derived1) -> None:
            print("handle from AppX", d)
    
    
    class AppY(BasicApp[Derived2]):
        def handle(self, d: Derived2) -> None:
            print("handle from AppY", d)