Search code examples
pythonmypy

mypy: how to write type hints for a function that takes 2 positional arguments but it is enough that only 1 is passed?


Say that I have a function foo such that it is allowed to take arguments as it follows

foo(a,b) -> It is OK
foo(None,b) -> It is OK
foo (a, None) -> It is OK
foo(None,None) -> It is NOT OK!!!

How to write its signature, including its type hints?

At the moment I have written the type hints as

def foo(a:Optional[str], b:Optional[str]) -> str

but that is wrong because such signature would be fine with the call foo(None,None).


Solution

  • Use @overload to define different (narrower) signatures for a function. Mypy will check calls to that function against all the overloaded signatures and produce an error if none of them match.

    from typing import overload, Optional
    
    @overload
    def foo(a: str, b: Optional[str]) -> str: ...
    
    @overload
    def foo(a: Optional[str], b: str) -> str: ...
    
    def foo(a: Optional[str], b: Optional[str]) -> str:
        return (a or "") + (b or "")
    
    foo('a', 'b') 
    foo(None, 'b')
    foo ('a', None)
    foo(None, None)  # error: No overload variant of "foo" matches argument types "None", "None"