-
Notifications
You must be signed in to change notification settings - Fork 125
Description
In the ecosystem, we see this kind of pattern:
def f(a: int, b: str): ...
x = { "a": 1, "b": "2" }
# Expected `int` found `Unknown | int | str`
f(x["a"], x["b"])
# or
f(**x)
In this case, an un-annotated dict literal is used implicitly as a heterogeneous TypedDict
. We (along with mypy and pyrefly) throw errors on these calls, because we infer the type of x
as dict[str, Unknown | int | str]
. (Pyrefly infers dict[str, int | str]
, mypy dict[str, object]
.)
Pyright avoids this problem by falling back to dict[str, Unknown]
rather than inferring a union value type, when the dict contents look heterogeneous.
A similar problem can occur with list literals (e.g. x = [1, "a"]; f(x[0], x[1])
). We do see this in the ecosystem too, but it's less common than with dictionaries (probably because tuples are an attractive alternative, and implicit heterogeneity is supported for tuples).
Perhaps ideally this would be solved by inferring a more precise heterogeneous "implicit TypedDict" type for these literals, but this gets very difficult to handle correctly with mutations.
If we do implement a "gradual mode" vs "strict mode", it may be worth emulating pyright's behavior in the "gradual mode".