Closed ZeeD closed 6 days ago
One wrinkle is that Small
allows deleting keys whereas Big
does not, which makes passing a Big
where a Small
is expected potentially unsound.
Consider:
from typing import NotRequired, TypedDict
class Big(TypedDict):
a: str
b: str
class Small(TypedDict):
a: NotRequired[str]
def foo(small: Small) -> None:
del small["a"] # ok, deleting NotRequired keys is permitted
x = Big(a="a", b="b")
foo(x) # danger! If this was legal, x would no longer be a valid Big
However, if you prevent key deletion using ReadOnly
, I think this would be safe. Pyright seems to support this, provided that the NotRequired
fields are ReadOnly
: [pyright playground]
Thanks!
Bug Report
mypy play url
it seems that mypy doesn't "match" a
NotRequired
field with a normal one when duck typing 2 different typed dict:Let's say that I have a function
foo
that expect aSmall
TypedDict as parameterIn this
Small
TypedDict the fielda
is marked asNotRequired
.Elsewere I have another
Big
TypedDict with 2 fieldsa
, andb
, both required.but if I try to pass a
Big
dict instance to myfoo
function, mypy mark it as an error:main.py:21: error: Argument 1 to "foo" has incompatible type "Big"; expected "Small" [arg-type]
If I change the type of
Big.a
to aNotRequired[str]
, mypy is happy, however mypy should allow the original definition, as a "normal" field should be treated as a stricter, "smaller" version of a not required one