Consider this example that emulates dict.get: (https://mypy-play.net/?mypy=latest&python=3.12)
from typing import Any, reveal_type
class Map[K, V]:
def set(self, key: K, value: V) -> None: ...
def get[T](self, key: Any, default: T, /) -> V | T: ...
d_any: Map[str, Any] = Map()
reveal_type(d_any.get("key", None)) # Any | None ✅️
result: str = reveal_type(d_any.get("key", None)) # Any | str ❌️
# error: Argument 2 to "get" of "Map" has incompatible type "None"; expected "str"
mypys error message is misleading. None is a perfectly reasonable argument for the default value of d_any.get. The problem is that the return type Any | None is not assignable to str. It would make more sense if either:
mypy reports that Any | None cannot be assigned to str.
(e.g. by a two step approach: first try to solve with context and if that fails, use the return type that is inferred from the arguments alone)1
mypy reports that it cannot find a solution for the type variable T.
(e.g. single step that considers both constraints from arguments and context)
Consider this example that emulates
dict.get: (https://mypy-play.net/?mypy=latest&python=3.12)mypys error message is misleading.Noneis a perfectly reasonable argument for the default value ofd_any.get. The problem is that the return typeAny | Noneis not assignable tostr. It would make more sense if either:mypyreports thatAny | Nonecannot be assigned tostr.(e.g. by a two step approach: first try to solve with context and if that fails, use the return type that is inferred from the arguments alone)1
mypyreports that it cannot find a solution for the type variableT.(e.g. single step that considers both constraints from arguments and context)
Footnotes
In certain special cases like tuple/list/set/dict-comprehensions, the current behavior that inverts the priority seems fine ↩