Consider these two similar functions:
```
from typing import Union

def f() -> int:
    x: Union[int, str] = 42
    return x  # Error here

def g() -> int:
    x: Union[int, str]
    x = 42
    return x  # But not here
```
Quite a while ago (2016-2017) there was a long discussion about this in the mypy tracker: https://github.com/python/mypy/issues/2008

Not only is it surprising that these two functions are type-checked differently, there are differences across type checkers. I tried mypy, pytype, pyre and pyright. All of them consider the second function correct. But all except pyright produce a type error on the first function, something along the lines of
```
t.py:5: error: Incompatible return value type (got "Union[int, str]", expected "int")
```
(It's possible that there are configuration settings to change the behavior; I didn't look into this.)

I think it would be in everybody's interest if all type checkers agreed on this. I also think it's surprising to users that the two functions are treated differently. (But as the old mypy issue shows, not everybody agrees they should be treated the same either. :-)

There's another twist (note the return type is str here):
```
from typing import Any

def h() -> str:
    x: Any = 42
    return x
```
This is an error in pyre but not in mypy, pytype or pyright. And for good measure the other variant:
```
def i() -> str:
    x: Any
    x = 42
    return x
```
This is accepted by mypy and pyright, but an error to pyre and pytype.

To summarize, it seems the type of x will be as follows:
```
x: Union[int, str] = 42
# mypy: Union; pytype: Union; pyre: Union; pyright: int
# majority doesn't narrow

x: Union[int, str]
x = 42
# mypy: int; pytype: int; pyre: int; pyright: int
# everybody narrows

x: Any = 42
# mypy: Any; pytype: Any; pyre: int; pyright: Any
# majority doesn't narrow

x: Any
x = 42
# mypy: Any; pytype: int; pyre: int; pyright: Any
# even split
```

Looking at this, I'd say if we follow the majority, we would have to make the following changes:

- pyright should stop narrowing for `x: Union[..] = value`
- pyre should stop narrowing for `x: Any = value`
- mypy and pyright should start narrowing for `x: Any; x = value`

(The latter recommendation is debatable, since it's an even split, but I like it better if Union and Any are treated similarly in this case.)

Let the debate begin.

--
--Guido van Rossum (python.org/~guido)