pythonpython-typing

Proper Python type hinting for this function in 2025


I'm using VS Code with Pylance, and having problems correctly writing type hints for the following function. To me, the semantics seem clear, but Pylance disagrees. How can I fix this without resorting to cast() or # type ignore? Pylance warnings are given in the comments.

I am fully committed to typing in Python, but it is often a struggle.

T = TypeVar("T")

def listify(item: T | list[T] | tuple[T, ...] | None) -> list[T]:
    if item is None:
        return []
    elif isinstance(item, list):
        return item             # Return type, "List[Unknown]* | List[T@listify]", 
                                # is partially unknown
    elif isinstance(item, tuple):
        return list(item)       # Return type, "List[Unknown]* | List[T@listify]",
                                # is partially unknown
    else:
        return [item]

Solution

  • This is just fundamentally unsafe, due to ambiguity.

    Suppose you have a generic function that uses listify:

    def caller[T](x: T):
        y = listify(x)
    

    What's the proper annotation for y?

    The obvious answer is list[T]. But there's no guarantee listify will return a list[T]. If T is list[Something], or tuple[Something, ...], or None, listify can return something completely different.


    There is no way to make a fully generic listify safe. Pylance does a stricter job than mypy of reporting this kind of ambiguity, but the fundamental ambiguity is there no matter what type checker you use.

    And even if you completely strip out the implementation, and simplify it down to

    def f[T](x: T | list[T]) -> list[T]:
        raise NotImplementedError
    
    reveal_type(f([3]))
    

    mypy will report the following:

    main.py:4: note: Revealed type is "builtins.list[Never]"
    main.py:4: error: Argument 1 to "f" has incompatible type "list[int]"; expected "list[Never]"  [arg-type]
    Found 1 error in 1 file (checked 1 source file)
    

    because the ambiguity is causing it to deduce conflicting type requirements.