classParent: defhello(self) -> int: # Revealed type is "def () -> builtins.int" return0 defoverride(self) -> int: # Revealed type is "def () -> builtins.int" return0
classChild(Parent): defoverride(self) -> str: # error: Return type "str" of "override" incompatible with return type "int" in supertype "Parent" return"override"
Pyright
classParent: defhello(self) -> int: # Type of "Parent().hello" is "() -> int" return0 defoverride(self) -> int: # Type of "Parent().override" is "() -> int" return0
classChild(Parent): defoverride(self) -> str: # Type of "Child().override" is "() -> str" return"override"
deffunc(a: int): # Revealed type is "def (a: builtins.int) -> Any" return a # Revealed type is "builtins.int"
Pyright
deffunc(a: int): # Type of "func" is "(a: int) -> int" return a # Type of "a" is "int"
引数の型から推論をすれば func は明らかに (int) -> int となりますが、Mypy は推論を行わないようになっており、戻り値の型が Any になります。
実験 4: 戻り値の型チェック
Mypy
deffunc(a: int) -> str: # Revealed type is "def (a: builtins.int) -> builtins.str" return a # error: Incompatible return value type (got "int", expected "str")
Pyright
deffunc(a: int) -> str: # Type of "func" is "(a: int) -> str" return a # error: Expression of type "int" cannot be assigned to return type "str" "int" is incompatible with "str" (reportGeneralTypeIssues)
deffunc(flg: bool, i: int, j: str): # Revealed type is "def (flg: builtins.bool, i: builtins.int, j: builtins.str) -> Any" if flg: a = i # Revealed type is "builtins.int" else: a = j # error: Incompatible types in assignment (expression has type "str", variable has type "int") return a # Revealed type is "builtins.int"
Pyright
deffunc(flg: bool, i: int, j: str): # Type of "func" is "(flg: bool, i: int, j: str) -> (int | str)" if flg: a = i # Type of "a" is "int" else: a = j # Type of "a" is "str" return a # Type of "a" is "int | str"
Pyright はエラーが出ません。分岐ごとに a の型を独立に判断し、戻り値の段階ではこれらの和を取っています。このような技術は Pyright のドキュメント内で Type Narrowing として紹介されています。
実験 6: タイプナローイング(到達不能な分岐がある場合)
Mypy
deffunc(flg: bool, i: int, j: str): # Revealed type is "def (flg: builtins.bool, i: builtins.int, j: builtins.str) -> Any" if flg: # Revealed type is "builtins.bool" a = i # Revealed type is "builtins.int" elifnot flg: # Revealed type is "builtins.bool" a = j # error: Incompatible types in assignment (expression has type "str", variable has type "int") else: # Revealed type is "builtins.bool" reveal_type(a) # Revealed type is "builtins.int" pass return a # Revealed type is "builtins.int"
Pyright
deffunc(flg: bool, i: int, j: str): # Type of "func" is "(flg: bool, i: int, j: str) -> (int | str)" if flg: # Type of "flg" is "Literal[True]" a = i # Type of "a" is "int" elifnot flg: # Type of "flg" is "Literal[False]" a = j # Type of "a" is "str" else: # Type of "flg" is "Never" reveal_type(a) # error: "a" is possibly unbound (reportUnboundVariable) pass return a # Type of "a" is "int | str | Unbound"