Search code examples
pythonpython-typingmypy

What is the correct way of using typing.Literal?


My code looks something like this, which runs fine BDW without any errors

from typing import Literal

def verify(word: str) -> Literal['Hello XY']:
    a = 'Hello ' + word
    return a

a = verify('XY')

Although, when I'm trying to do the type-checking using mypy, it throws an error error: Incompatible return value type (got "str", expected "Literal['Hello XY']")

NOTE: To perform type-checking simply do mypy ./filename.py, after pip installing mypy.

ALSO, When I do this, the type-checking works fine

from typing import Literal

def verify(word: str) -> Literal['Hello XY']:
    a = 'Hello ' + word
    return 'Hello XY' #changed here

a = verify('XY')

What am I missing?


Solution

  • word can be any string, so this seems like a good thing that mypy complains because it cannot guess that you will always call it with the appropriate argument. In other words, for mypy, if you concatenate 'Hello ' with some str, it can give any str and not only 'Hello XY'.

    What you could do to check if the function is called appropriately, is instead to type word with a literal:

    from typing import Literal, cast
    
    hello_t = Literal['Hello there', 'Hello world']
    
    def verify(word: Literal['there', 'world']) -> hello_t:
        a = cast(hello_t, 'Hello ' + word)
        return a
    
    a = verify('there')  # mypy OK
    a = verify('world')  # mypy OK
    a = verify('you')  # mypy error
    

    Note that a cast is still required because mypy cannot guess that the concatenation of 'Hello ' with a Literal['there', 'world'] is of type hello_t.