-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Closed
Labels
Description
Bug Report
Inheriting from a generic TypedDict with a T | None key inexplicably narrows the that key type to T.
To Reproduce
from typing import Generic, TypeVar, TypedDict
T = TypeVar("T")
class Foo(TypedDict, Generic[T], total=False):
a: str | None
...
class Bar(Foo[T], total=False):
...
class Baz(Foo[int], total=False):
...
a_value: str | None
foo: Foo[int]
bar: Bar[int]
baz: Baz
reveal_type(foo) # TypedDict('tests.Foo', {'a'?: Union[builtins.str, None]})
reveal_type(bar) # TypedDict('tests.Bar', {'a'?: builtins.str})
reveal_type(baz) # TypedDict('tests.Baz', {'a'?: builtins.str})
foo["a"] = a_value # passes
bar["a"] = a_value # error: Value of "a" has incompatible type "str | None"; expected "str" [typeddict-item]
baz["a"] = a_value # error: Value of "a" has incompatible type "str | None"; expected "str" [typeddict-item]Expected Behavior
No errors. For all three variables foo, bar, baz the revealed type of the a-key of the TypedDict should be Union[builtins.str, None].
Actual Behavior
The type of the a-key of bar and baz is revealed to be builtins.str instead of Union[builtins.str, None].
Thus, the last two assignments cause the errors:
error: Value of "a" has incompatible type "int | None"; expected "int" [typeddict-item]
error: Value of "a" has incompatible type "int | None"; expected "int" [typeddict-item]
Notable obsevations
- It does not matter, if any key in
Foois actually declared to be of typeT. - Declaring for example
a: T | Noneand adjusting thea_valuetype accordingly makes no difference. - As soon as you make
Foonon-generic, i.e. removeGeneric[T]from the bases (and adjustBarandBazdeclarations accordingly), the error disappears. - If you declare the
a-key to be of any other union type e.g.str | int(and adjust thea_valuetype accordingly), the error seems to disappear. (Obviously I have only tested a few combinations.)
Your Environment
- Mypy version used:
1.6.1 - Mypy command-line flags: -
- Mypy configuration options from
mypy.ini(and other config files):strict = True - Python version used:
3.11.4(also reproduced with3.9.17)