Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mypy reports parameter whose type is a TypeVar bound to the same type as its default value's

When annotating a function parameter with a bound TypeVar, giving it a default value results in the parameter having a union type between the TypeVar and the default value type, even though the default value is of the TypeVar type.

Example:

class A:
    pass

class B(A):
    pass

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

def get_instance(cls: type[Instance] = A) -> Instance:
    return cls()

Running mypy yields the following error: error: Incompatible default for argument "cls" (default has type "Type[A]", argument has type "Type[Instance]").

reveal_type is correct in both cases:

instance_a = get_instance(cls=A)
reveal_type(instance_a)  # note: Revealed type is "A"

instance_b = get_instance(cls=B)
reveal_type(instance_b)  # note: Revealed type is "B"

How do I correctly annotate get_instance so that I can keep the default argument?

like image 856
connesy Avatar asked Oct 21 '25 14:10

connesy


1 Answers

It is a very old mypy issue.

The general solution is using overload's, it can be applied in your case:

from typing import TypeVar, overload

class A:
    pass

class B(A):
    pass

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

@overload
def get_instance() -> A: ...
@overload
def get_instance(cls: type[_Instance]) -> _Instance: ...
def get_instance(cls: type[A] = A) -> A:
    return cls()

instance_a = get_instance(cls=A)
reveal_type(instance_a)  # note: Revealed type is "A"

instance_b = get_instance(cls=B)
reveal_type(instance_b)  # note: Revealed type is "B"

For type checking purposes, we define two overloads. Implementation signature is checked only within the function, external callers see only the overloads. Here we just ignore specific relationship between cls type and return type while checking body, however, you can consider other solutions from the linked issue.

Try me in playground

like image 157
STerliakov Avatar answered Oct 24 '25 04:10

STerliakov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!