pythonpython-typingpyright

When is typing.cast required?


Here's the code

# args: argparse.Namespace
source: str = args.source

...

# subparsers: argparse._SubParsersAction
parser = subparsers.add_parser()

In the first line of code, : str is enough to tell Pylance that source is a string, although args.source is Any.

However, in the second line, when I add : argparse.ArgumentParser, the type of parser is still Any | argparse.ArgumentParser. I have to manually use cast(argparse.ArgumentParser) to get the desired effect, since add_parser() is typed as returing Any.

Why is that the case? Both are assignment to me, one from a field, one from the return of a function.


Solution

  • In the schematic LEFT = RIGHT, if RIGHT is not assignable to LEFT, then it "needs a cast"*.

    This also applies to a function's return type as follows:

    def f(...) -> <type of LEFT>:
        return RIGHT
    

    Some general examples:

    As for your examples in the question:


    * Of course, in some situations, you don't actually "need a cast" - an explicit type annotation along with a # type: ignore or # pyright: ignore[<some error code>] will work just fine, along with turning on reportUnnecessaryTypeIgnoreComment to warn unnecessary ignore comments. This prevents the need of an extra runtime variable lookup and call to typing.cast.