The following code appears to generate two mypy errors: Overloaded function signatures 1 and 3 overlap with incompatible return types
and Overloaded function signatures 2 and 3 overlap with incompatible return types
; but all overloads have different signatures - Literal[True], Literal[False] and None do not overlap.
@overload
def func_a(*, a: Literal[False] = ...) -> str:
...
@overload
def func_a(*, a: None = ...) -> str:
...
@overload
def func_a(*, a: Literal[True] = ...) -> int:
...
def func_a(*, a: Optional[bool] = None) -> str | int:
if a:
return 1
return "foo"
var1 = func_a() # str correctly discovered by VSCode Pylance
var2 = func_a(a=False) # str correctly discovered by VSCode Pylance
var3 = func_a(a=True) # int correctly discovered by VSCode Pylance
Why does Mypy think they overlap and how could I go about fixing this?
Mypy version: 0.991
Python version: 3.11.1
The problem is that by writing = ...
default values for every overload, you've marked the parameter as optional in every overload. A plain func_a()
call matches every single overload of your function.
You need to resolve that, so func_a()
only matches one overload. Here's one way:
@overload
def func_a(*, a: Literal[False]) -> str:
...
@overload
def func_a(*, a: Literal[True]) -> int:
...
@overload
def func_a(*, a: None = None) -> str:
...
Here, only the None
overload marks the parameter as optional, so func_a()
only matches that overload.
Alternatively, you could make the no-argument version its own overload:
@overload
def func_a(*, a: Literal[False]) -> str:
...
@overload
def func_a(*, a: Literal[True]) -> int:
...
@overload
def func_a(*, a: None) -> str:
...
@overload
def func_a() -> str:
...