2Tests the type consistency rules for TypedDict objects.
5# Specification: https://typing.readthedocs.io/en/latest/spec/typeddict.html#type-consistency
7from typing import Any, Literal, Mapping, TypedDict
20# > Value types behave invariantly.
21a1: A1 = b1 # E: 'B1' not compatible with 'A1'
[invalid-assignment] Object of type `B1` is not assignable to `A1`
23# > any TypedDict type is consistent with Mapping[str, object]
24v1: Mapping[str, object] = b1
26# > A TypedDict type with a required key is not consistent with a TypedDict
27# > type where the same key is a non-required key.
29class A2(TypedDict, total=False):
38a2: A2 = b2 # E: 'B2' not compatible with 'A2'
[invalid-assignment] Object of type `B2` is not assignable to `A2`
41# > A TypedDict type A is consistent with TypedDict B if A is structurally
42# > compatible with B. This is true if and only if both of these conditions
44# > 1. For each key in B, A has the corresponding key and the corresponding
45# > value type in A is consistent with the value type in B. For each key in B,
46# > the value type in B is also consistent with the corresponding value type
48# > 2. For each required key in B, the corresponding key is required in A. For
49# > each non-required key in B, the corresponding key is not required in A.
61b3: B3 = {"x": 0, "y": 0}
[invalid-assignment] Object of type `A3` is not assignable to `B3`
68# This should generate an error because it's a literal assignment.
69a3_1: A3 = {"x": 0, "y": 0} # E
[invalid-key] Unknown key "y" for TypedDict `A3`: Unknown key "y"
71# This should not generate an error.
74# > A TypedDict isn’t consistent with any Dict[...] type.
76d1: dict[str, int] = b3 # E
[invalid-assignment] Object of type `B3` is not assignable to `dict[str, int]`
77d2: dict[str, object] = b3 # E
[invalid-assignment] Object of type `B3` is not assignable to `dict[str, object]`
78d3: dict[Any, Any] = b3 # E
[invalid-assignment] Object of type `B3` is not assignable to `dict[Any, Any]`
80# > A TypedDict with all int values is not consistent with Mapping[str, int].
82m1: Mapping[str, int] = b3 # E
[invalid-assignment] Object of type `B3` is not assignable to `Mapping[str, int]`
83m2: Mapping[str, object] = b3 # OK
84m3: Mapping[str, Any] = b3 # OK
88UserType1 = TypedDict("UserType1", {"name": str, "age": int}, total=False)
89user1: UserType1 = {"name": "Bob", "age": 40}
91name1: str = user1.get("name", "n/a")
92age1: int = user1.get("age", 42)
94UserType2 = TypedDict("UserType2", {"name": str, "age": int})
95user2: UserType2 = {"name": "Bob", "age": 40}
97name2: str | None = user2.get("name")
99# The spec does not say whether type checkers should adjust the return type of `.get()`
100# to exclude `None` if it is known that the key exists. Either option is acceptable.
101name3: str = user2.get("name") # E?
[invalid-assignment] Object of type `Unknown | None` is not assignable to `str`
103age2: int = user2.get("age", 42)
105age3: int | str = user2.get("age", "42")
107age4: int = user2.get("age", "42") # E?
109# Test nested TypedDicts.
110class Inner1(TypedDict):
114class Inner2(TypedDict):
118class Outer1(TypedDict):
122o1: Outer1 = {"outer_key": {"inner_key": {"inner_key": "hi"}}}
124# This should generate an error because the inner-most value
126o2: Outer1 = {"outer_key": {"inner_key": {"inner_key": 1}}} # E
[invalid-argument-type] Invalid argument to key "inner_key" with declared type `str` on TypedDict `Inner1`: value of type `Literal[1]`
129class Inner3(TypedDict):
133class Inner4(TypedDict):
137class Outer2(TypedDict):
139 z: Literal[""] | Inner3
142class Outer3(TypedDict):
144 z: Literal[""] | Inner4
147def func1(td: Outer3):
151o3: Outer2 = {"y": "", "z": {"x": 0}}