You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Inheriting from a generic TypedDict with a T | None key inexplicably narrows the that key type to T #16395
Inheriting from a generic TypedDict with a T | None key inexplicably narrows the that key type to T.
To Reproduce
fromtypingimportGeneric, TypeVar, TypedDictT=TypeVar("T")
classFoo(TypedDict, Generic[T], total=False):
a: str|None
...
classBar(Foo[T], total=False):
...
classBaz(Foo[int], total=False):
...
a_value: str|Nonefoo: Foo[int]
bar: Bar[int]
baz: Bazreveal_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# passesbar["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 Foo is actually declared to be of type T.
Declaring for example a: T | None and adjusting the a_value type accordingly makes no difference.
As soon as you make Foo non-generic, i.e. remove Generic[T] from the bases (and adjust Bar and Baz declarations accordingly), the error disappears.
If you declare the a-key to be of any other union type e.g. str | int (and adjust the a_value type 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 with 3.9.17)
Activity
JelleZijlstra commentedon Nov 2, 2023
Confirmed in mypy playground: https://mypy-play.net/?mypy=latest&python=3.10&gist=4d53c16a3b06bad9014022b24b490d08
Feels like something is going wrong with strict-optional handling.
Fix strict-optional in extending generic TypedDict (#16398)