diff --git a/conformance/results/mypy/typeddicts_extra_items.toml b/conformance/results/mypy/typeddicts_extra_items.toml
new file mode 100644
index 00000000..9f1bde56
--- /dev/null
+++ b/conformance/results/mypy/typeddicts_extra_items.toml
@@ -0,0 +1,143 @@
+conformant = "Unsupported"
+notes = """
+Not supported.
+"""
+conformance_automated = "Fail"
+errors_diff = """
+Line 181: Expected 1 errors
+Line 184: Expected 1 errors
+Line 206: Expected 1 errors
+Line 213: Expected 1 errors
+Line 233: Expected 1 errors
+Line 247: Expected 1 errors
+Line 248: Expected 1 errors
+Line 259: Expected 1 errors
+Lines 91, 92: Expected error (tag 'MovieC')
+Lines 94, 95: Expected error (tag 'MovieD')
+Line 11: Unexpected errors ['typeddicts_extra_items.py:11: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 14: Unexpected errors ['typeddicts_extra_items.py:14: error: Extra key "novel_adaptation" for TypedDict "Movie" [typeddict-unknown-key]']
+Line 19: Unexpected errors ['typeddicts_extra_items.py:19: error: Unexpected keyword argument "extra_items" for "TypedDict" [misc]']
+Line 21: Unexpected errors ['typeddicts_extra_items.py:21: error: Extra keys ("name", "novel_adaptation") for TypedDict "MovieFunctional" [typeddict-unknown-key]']
+Line 29: Unexpected errors ['typeddicts_extra_items.py:29: error: Expression is of type "Any", not "bool" [assert-type]', 'typeddicts_extra_items.py:29: error: TypedDict "Movie" has no key "novel_adaptation" [typeddict-item]']
+Line 33: Unexpected errors ['typeddicts_extra_items.py:33: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 40: Unexpected errors ['typeddicts_extra_items.py:40: error: Extra key "other_extra_key" for TypedDict "InheritedMovie" [typeddict-unknown-key]']
+Line 55: Unexpected errors ['typeddicts_extra_items.py:55: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 64: Unexpected errors ['typeddicts_extra_items.py:64: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 70: Unexpected errors ['typeddicts_extra_items.py:70: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 82: Unexpected errors ['typeddicts_extra_items.py:82: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 88: Unexpected errors ['typeddicts_extra_items.py:88: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 100: Unexpected errors ['typeddicts_extra_items.py:100: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 103: Unexpected errors ['typeddicts_extra_items.py:103: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 106: Unexpected errors ['typeddicts_extra_items.py:106: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 121: Unexpected errors ['typeddicts_extra_items.py:121: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 126: Unexpected errors ['typeddicts_extra_items.py:126: error: TypedDict "MovieEI" has no key "year" [typeddict-item]']
+Line 134: Unexpected errors ['typeddicts_extra_items.py:134: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 141: Unexpected errors ['typeddicts_extra_items.py:141: error: Unexpected keyword argument "year" for "unpack_extra" [call-arg]']
+Line 146: Unexpected errors ['typeddicts_extra_items.py:146: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 149: Unexpected errors ['typeddicts_extra_items.py:149: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 152: Unexpected errors ['typeddicts_extra_items.py:152: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 162: Unexpected errors ['typeddicts_extra_items.py:162: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 168: Unexpected errors ['typeddicts_extra_items.py:168: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 178: Unexpected errors ['typeddicts_extra_items.py:178: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 201: Unexpected errors ['typeddicts_extra_items.py:201: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 208: Unexpected errors ['typeddicts_extra_items.py:208: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 219: Unexpected errors ['typeddicts_extra_items.py:219: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 222: Unexpected errors ['typeddicts_extra_items.py:222: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 226: Unexpected errors ['typeddicts_extra_items.py:226: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 239: Unexpected errors ['typeddicts_extra_items.py:239: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 242: Unexpected errors ['typeddicts_extra_items.py:242: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 245: Unexpected errors ['typeddicts_extra_items.py:245: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]']
+Line 246: Unexpected errors ['typeddicts_extra_items.py:246: error: Extra key "description" for TypedDict "MovieExtraStr" [typeddict-unknown-key]']
+Line 257: Unexpected errors ['typeddicts_extra_items.py:257: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]']
+Line 271: Unexpected errors ['typeddicts_extra_items.py:271: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 275: Unexpected errors ['typeddicts_extra_items.py:275: error: Extra key "year" for TypedDict "ExtraMovie" [typeddict-unknown-key]']
+Line 280: Unexpected errors ['typeddicts_extra_items.py:280: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 290: Unexpected errors ['typeddicts_extra_items.py:290: error: Extra key "summary" for TypedDict "MovieExtraStr" [typeddict-unknown-key]']
+Line 291: Unexpected errors ['typeddicts_extra_items.py:291: error: Incompatible types in assignment (expression has type "MovieExtraStr", variable has type "Mapping[str, str]") [assignment]']
+Line 293: Unexpected errors ['typeddicts_extra_items.py:293: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]']
+Line 295: Unexpected errors ['typeddicts_extra_items.py:295: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int | str]") [assignment]']
+Line 301: Unexpected errors ['typeddicts_extra_items.py:301: error: Expression is of type "list[tuple[str, object]]", not "list[tuple[str, int | str]]" [assert-type]']
+Line 302: Unexpected errors ['typeddicts_extra_items.py:302: error: Expression is of type "list[object]", not "list[int | str]" [assert-type]']
+Line 310: Unexpected errors ['typeddicts_extra_items.py:310: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]']
+Line 317: Unexpected errors ['typeddicts_extra_items.py:317: error: Incompatible types in assignment (expression has type "IntDict", variable has type "dict[str, int]") [assignment]']
+Line 320: Unexpected errors ['typeddicts_extra_items.py:320: error: Extra key "bar" for TypedDict "IntDictWithNum" [typeddict-unknown-key]']
+Line 321: Unexpected errors ['typeddicts_extra_items.py:321: error: Incompatible types in assignment (expression has type "IntDictWithNum", variable has type "dict[str, int]") [assignment]']
+Line 328: Unexpected errors ['typeddicts_extra_items.py:328: error: "IntDictWithNum" has no attribute "clear" [attr-defined]']
+Line 330: Unexpected errors ['typeddicts_extra_items.py:330: error: Expression is of type "Any", not "tuple[str, int]" [assert-type]', 'typeddicts_extra_items.py:330: error: "IntDictWithNum" has no attribute "popitem" [attr-defined]']
+Line 333: Unexpected errors ['typeddicts_extra_items.py:333: error: TypedDict key must be a string literal; expected one of ("num") [literal-required]']
+Line 334: Unexpected errors ['typeddicts_extra_items.py:334: error: Expected TypedDict key to be string literal [misc]']
+"""
+output = """
+typeddicts_extra_items.py:11: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:14: error: Extra key "novel_adaptation" for TypedDict "Movie" [typeddict-unknown-key]
+typeddicts_extra_items.py:15: error: Extra key "year" for TypedDict "Movie" [typeddict-unknown-key]
+typeddicts_extra_items.py:19: error: Unexpected keyword argument "extra_items" for "TypedDict" [misc]
+typeddicts_extra_items.py:21: error: Extra keys ("name", "novel_adaptation") for TypedDict "MovieFunctional" [typeddict-unknown-key]
+typeddicts_extra_items.py:22: error: Extra keys ("name", "year") for TypedDict "MovieFunctional" [typeddict-unknown-key]
+typeddicts_extra_items.py:29: error: Expression is of type "Any", not "bool" [assert-type]
+typeddicts_extra_items.py:29: error: TypedDict "Movie" has no key "novel_adaptation" [typeddict-item]
+typeddicts_extra_items.py:33: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:39: error: Incompatible types (expression has type "None", TypedDict item "year" has type "int") [typeddict-item]
+typeddicts_extra_items.py:40: error: Extra key "other_extra_key" for TypedDict "InheritedMovie" [typeddict-unknown-key]
+typeddicts_extra_items.py:49: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:55: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:64: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:67: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:70: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:73: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:82: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:88: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:100: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:103: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:106: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:111: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:114: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:121: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:125: error: Key "name" of TypedDict "MovieEI" cannot be deleted [misc]
+typeddicts_extra_items.py:126: error: TypedDict "MovieEI" has no key "year" [typeddict-item]
+typeddicts_extra_items.py:134: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:137: note: "unpack_no_extra" defined here
+typeddicts_extra_items.py:138: note: "unpack_extra" defined here
+typeddicts_extra_items.py:140: error: Unexpected keyword argument "year" for "unpack_no_extra" [call-arg]
+typeddicts_extra_items.py:141: error: Unexpected keyword argument "year" for "unpack_extra" [call-arg]
+typeddicts_extra_items.py:146: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:149: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:152: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:162: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:168: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:171: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:178: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:201: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:208: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:219: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:222: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:226: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:239: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:242: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:245: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]
+typeddicts_extra_items.py:246: error: Extra key "description" for TypedDict "MovieExtraStr" [typeddict-unknown-key]
+typeddicts_extra_items.py:257: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]
+typeddicts_extra_items.py:269: error: Extra key "year" for TypedDict "NonClosedMovie" [typeddict-unknown-key]
+typeddicts_extra_items.py:271: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:275: error: Extra key "year" for TypedDict "ExtraMovie" [typeddict-unknown-key]
+typeddicts_extra_items.py:276: error: Extra key "language" for TypedDict "ExtraMovie" [typeddict-unknown-key]
+typeddicts_extra_items.py:280: error: Unexpected keyword argument "closed" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:284: error: Extra key "year" for TypedDict "ClosedMovie" [typeddict-unknown-key]
+typeddicts_extra_items.py:290: error: Extra key "summary" for TypedDict "MovieExtraStr" [typeddict-unknown-key]
+typeddicts_extra_items.py:291: error: Incompatible types in assignment (expression has type "MovieExtraStr", variable has type "Mapping[str, str]") [assignment]
+typeddicts_extra_items.py:293: error: Extra key "year" for TypedDict "MovieExtraInt" [typeddict-unknown-key]
+typeddicts_extra_items.py:294: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int]") [assignment]
+typeddicts_extra_items.py:295: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int | str]") [assignment]
+typeddicts_extra_items.py:301: error: Expression is of type "list[tuple[str, object]]", not "list[tuple[str, int | str]]" [assert-type]
+typeddicts_extra_items.py:302: error: Expression is of type "list[object]", not "list[int | str]" [assert-type]
+typeddicts_extra_items.py:310: error: Unexpected keyword argument "extra_items" for "__init_subclass__" of "TypedDict" [call-arg]
+typeddicts_extra_items.py:317: error: Incompatible types in assignment (expression has type "IntDict", variable has type "dict[str, int]") [assignment]
+typeddicts_extra_items.py:320: error: Extra key "bar" for TypedDict "IntDictWithNum" [typeddict-unknown-key]
+typeddicts_extra_items.py:321: error: Incompatible types in assignment (expression has type "IntDictWithNum", variable has type "dict[str, int]") [assignment]
+typeddicts_extra_items.py:328: error: "IntDictWithNum" has no attribute "clear" [attr-defined]
+typeddicts_extra_items.py:330: error: Expression is of type "Any", not "tuple[str, int]" [assert-type]
+typeddicts_extra_items.py:330: error: "IntDictWithNum" has no attribute "popitem" [attr-defined]
+typeddicts_extra_items.py:333: error: TypedDict key must be a string literal; expected one of ("num") [literal-required]
+typeddicts_extra_items.py:334: error: Expected TypedDict key to be string literal [misc]
+typeddicts_extra_items.py:343: error: Incompatible types in assignment (expression has type "dict[str, int]", variable has type "IntDict") [assignment]
+"""
diff --git a/conformance/results/pyre/typeddicts_extra_items.toml b/conformance/results/pyre/typeddicts_extra_items.toml
new file mode 100644
index 00000000..aa91c7f4
--- /dev/null
+++ b/conformance/results/pyre/typeddicts_extra_items.toml
@@ -0,0 +1,139 @@
+conformant = "Unsupported"
+notes = """
+Not supported.
+"""
+conformance_automated = "Fail"
+errors_diff = """
+Line 181: Expected 1 errors
+Line 184: Expected 1 errors
+Line 206: Expected 1 errors
+Line 213: Expected 1 errors
+Line 233: Expected 1 errors
+Line 247: Expected 1 errors
+Line 248: Expected 1 errors
+Line 259: Expected 1 errors
+Lines 91, 92: Expected error (tag 'MovieC')
+Lines 94, 95: Expected error (tag 'MovieD')
+Line 11: Unexpected errors ['typeddicts_extra_items.py:11:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 14: Unexpected errors ['typeddicts_extra_items.py:14:11 TypedDict initialization error [55]: TypedDict `Movie` has no field `novel_adaptation`.']
+Line 21: Unexpected errors ['typeddicts_extra_items.py:21:21 TypedDict initialization error [55]: TypedDict `MovieFunctional` has no field `novel_adaptation`.']
+Line 29: Unexpected errors ['typeddicts_extra_items.py:29:4 Assert type [70]: Expected `bool` but got `str`.', 'typeddicts_extra_items.py:29:22 TypedDict accessed with a missing key [27]: TypedDict `Movie` has no key `novel_adaptation`.']
+Line 33: Unexpected errors ['typeddicts_extra_items.py:33:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 40: Unexpected errors ['typeddicts_extra_items.py:40:20 TypedDict initialization error [55]: TypedDict `InheritedMovie` has no field `other_extra_key`.']
+Line 55: Unexpected errors ['typeddicts_extra_items.py:55:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 64: Unexpected errors ['typeddicts_extra_items.py:64:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 70: Unexpected errors ['typeddicts_extra_items.py:70:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 82: Unexpected errors ['typeddicts_extra_items.py:82:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 88: Unexpected errors ['typeddicts_extra_items.py:88:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 100: Unexpected errors ['typeddicts_extra_items.py:100:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 103: Unexpected errors ['typeddicts_extra_items.py:103:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 106: Unexpected errors ['typeddicts_extra_items.py:106:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 121: Unexpected errors ['typeddicts_extra_items.py:121:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 126: Unexpected errors ['typeddicts_extra_items.py:126:14 TypedDict accessed with a missing key [27]: TypedDict `MovieEI` has no key `year`.']
+Line 134: Unexpected errors ['typeddicts_extra_items.py:134:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 141: Unexpected errors ['typeddicts_extra_items.py:141:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `unpack_extra`.']
+Line 146: Unexpected errors ['typeddicts_extra_items.py:146:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 149: Unexpected errors ['typeddicts_extra_items.py:149:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 152: Unexpected errors ['typeddicts_extra_items.py:152:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 162: Unexpected errors ['typeddicts_extra_items.py:162:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 168: Unexpected errors ['typeddicts_extra_items.py:168:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 178: Unexpected errors ['typeddicts_extra_items.py:178:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 201: Unexpected errors ['typeddicts_extra_items.py:201:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 208: Unexpected errors ['typeddicts_extra_items.py:208:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 219: Unexpected errors ['typeddicts_extra_items.py:219:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 222: Unexpected errors ['typeddicts_extra_items.py:222:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 226: Unexpected errors ['typeddicts_extra_items.py:226:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 239: Unexpected errors ['typeddicts_extra_items.py:239:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 242: Unexpected errors ['typeddicts_extra_items.py:242:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 245: Unexpected errors ['typeddicts_extra_items.py:245:27 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.']
+Line 246: Unexpected errors ['typeddicts_extra_items.py:246:27 TypedDict initialization error [55]: TypedDict `MovieExtraStr` has no field `description`.']
+Line 257: Unexpected errors ['typeddicts_extra_items.py:257:28 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.']
+Line 271: Unexpected errors ['typeddicts_extra_items.py:271:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 275: Unexpected errors ['typeddicts_extra_items.py:275:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `ExtraMovie.__init__`.']
+Line 280: Unexpected errors ['typeddicts_extra_items.py:280:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.']
+Line 290: Unexpected errors ['typeddicts_extra_items.py:290:28 TypedDict initialization error [55]: TypedDict `MovieExtraStr` has no field `summary`.']
+Line 291: Unexpected errors ['typeddicts_extra_items.py:291:0 Incompatible variable type [9]: str_mapping is declared to have type `Mapping[str, str]` but is used as type `MovieExtraStr`.']
+Line 293: Unexpected errors ['typeddicts_extra_items.py:293:28 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.']
+Line 295: Unexpected errors ['typeddicts_extra_items.py:295:0 Incompatible variable type [9]: int_str_mapping is declared to have type `Mapping[str, Union[int, str]]` but is used as type `MovieExtraInt`.']
+Line 301: Unexpected errors ['typeddicts_extra_items.py:301:4 Assert type [70]: Expected `List[Tuple[str, Union[int, str]]]` but got `List[Tuple[str, object]]`.']
+Line 302: Unexpected errors ['typeddicts_extra_items.py:302:4 Assert type [70]: Expected `List[Union[int, str]]` but got `List[object]`.']
+Line 310: Unexpected errors ['typeddicts_extra_items.py:310:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.']
+Line 317: Unexpected errors ['typeddicts_extra_items.py:317:4 Incompatible variable type [9]: v is declared to have type `Dict[str, int]` but is used as type `IntDict`.']
+Line 320: Unexpected errors ['typeddicts_extra_items.py:320:40 TypedDict initialization error [55]: TypedDict `IntDictWithNum` has no field `bar`.']
+Line 321: Unexpected errors ['typeddicts_extra_items.py:321:0 Incompatible variable type [9]: regular_dict is declared to have type `Dict[str, int]` but is used as type `IntDictWithNum`.']
+Line 328: Unexpected errors ['typeddicts_extra_items.py:328:0 Undefined attribute [16]: `IntDictWithNum` has no attribute `clear`.']
+Line 330: Unexpected errors ['typeddicts_extra_items.py:330:0 Assert type [70]: Expected `Tuple[str, int]` but got `typing.Any`.', 'typeddicts_extra_items.py:330:12 Undefined attribute [16]: `IntDictWithNum` has no attribute `popitem`.']
+Line 333: Unexpected errors ["typeddicts_extra_items.py:333:26 TypedDict accessed with a non-literal [26]: TypedDict key must be a string literal. Expected one of ('num')."]
+Line 334: Unexpected errors ["typeddicts_extra_items.py:334:30 TypedDict accessed with a non-literal [26]: TypedDict key must be a string literal. Expected one of ('num')."]
+"""
+output = """
+typeddicts_extra_items.py:11:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:14:11 TypedDict initialization error [55]: TypedDict `Movie` has no field `novel_adaptation`.
+typeddicts_extra_items.py:15:11 TypedDict initialization error [55]: TypedDict `Movie` has no field `year`.
+typeddicts_extra_items.py:21:21 TypedDict initialization error [55]: TypedDict `MovieFunctional` has no field `novel_adaptation`.
+typeddicts_extra_items.py:22:21 TypedDict initialization error [55]: TypedDict `MovieFunctional` has no field `year`.
+typeddicts_extra_items.py:29:4 Assert type [70]: Expected `bool` but got `str`.
+typeddicts_extra_items.py:29:22 TypedDict accessed with a missing key [27]: TypedDict `Movie` has no key `novel_adaptation`.
+typeddicts_extra_items.py:33:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:39:20 TypedDict initialization error [55]: Expected type `int` for `InheritedMovie` field `year` but got `None`.
+typeddicts_extra_items.py:40:20 TypedDict initialization error [55]: TypedDict `InheritedMovie` has no field `other_extra_key`.
+typeddicts_extra_items.py:49:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:55:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:64:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:67:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:70:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:73:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:82:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:88:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:100:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:103:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:106:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:111:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:114:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:121:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:125:4 Invalid TypedDict operation [54]: Cannot delete required field `name` from TypedDict `MovieEI`.
+typeddicts_extra_items.py:126:14 TypedDict accessed with a missing key [27]: TypedDict `MovieEI` has no key `year`.
+typeddicts_extra_items.py:134:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:140:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `unpack_no_extra`.
+typeddicts_extra_items.py:141:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `unpack_extra`.
+typeddicts_extra_items.py:146:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:149:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:152:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:162:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:168:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:171:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:178:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:201:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:208:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:219:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:222:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:226:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:239:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:242:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:245:27 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.
+typeddicts_extra_items.py:246:27 TypedDict initialization error [55]: TypedDict `MovieExtraStr` has no field `description`.
+typeddicts_extra_items.py:257:28 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.
+typeddicts_extra_items.py:269:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `NonClosedMovie.__init__`.
+typeddicts_extra_items.py:271:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:275:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `ExtraMovie.__init__`.
+typeddicts_extra_items.py:276:0 Unexpected keyword [28]: Unexpected keyword argument `language` to call `ExtraMovie.__init__`.
+typeddicts_extra_items.py:280:0 Unexpected keyword [28]: Unexpected keyword argument `closed` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:284:0 Unexpected keyword [28]: Unexpected keyword argument `year` to call `ClosedMovie.__init__`.
+typeddicts_extra_items.py:290:28 TypedDict initialization error [55]: TypedDict `MovieExtraStr` has no field `summary`.
+typeddicts_extra_items.py:291:0 Incompatible variable type [9]: str_mapping is declared to have type `Mapping[str, str]` but is used as type `MovieExtraStr`.
+typeddicts_extra_items.py:293:28 TypedDict initialization error [55]: TypedDict `MovieExtraInt` has no field `year`.
+typeddicts_extra_items.py:294:0 Incompatible variable type [9]: int_mapping is declared to have type `Mapping[str, int]` but is used as type `MovieExtraInt`.
+typeddicts_extra_items.py:295:0 Incompatible variable type [9]: int_str_mapping is declared to have type `Mapping[str, Union[int, str]]` but is used as type `MovieExtraInt`.
+typeddicts_extra_items.py:301:4 Assert type [70]: Expected `List[Tuple[str, Union[int, str]]]` but got `List[Tuple[str, object]]`.
+typeddicts_extra_items.py:302:4 Assert type [70]: Expected `List[Union[int, str]]` but got `List[object]`.
+typeddicts_extra_items.py:310:0 Unexpected keyword [28]: Unexpected keyword argument `extra_items` to call `object.__init_subclass__`.
+typeddicts_extra_items.py:317:4 Incompatible variable type [9]: v is declared to have type `Dict[str, int]` but is used as type `IntDict`.
+typeddicts_extra_items.py:320:40 TypedDict initialization error [55]: TypedDict `IntDictWithNum` has no field `bar`.
+typeddicts_extra_items.py:321:0 Incompatible variable type [9]: regular_dict is declared to have type `Dict[str, int]` but is used as type `IntDictWithNum`.
+typeddicts_extra_items.py:328:0 Undefined attribute [16]: `IntDictWithNum` has no attribute `clear`.
+typeddicts_extra_items.py:330:0 Assert type [70]: Expected `Tuple[str, int]` but got `typing.Any`.
+typeddicts_extra_items.py:330:12 Undefined attribute [16]: `IntDictWithNum` has no attribute `popitem`.
+typeddicts_extra_items.py:333:26 TypedDict accessed with a non-literal [26]: TypedDict key must be a string literal. Expected one of ('num').
+typeddicts_extra_items.py:334:30 TypedDict accessed with a non-literal [26]: TypedDict key must be a string literal. Expected one of ('num').
+typeddicts_extra_items.py:343:4 Incompatible variable type [9]: int_dict is declared to have type `IntDict` but is used as type `Dict[str, int]`.
+"""
diff --git a/conformance/results/pyright/typeddicts_extra_items.toml b/conformance/results/pyright/typeddicts_extra_items.toml
new file mode 100644
index 00000000..8bdb0fab
--- /dev/null
+++ b/conformance/results/pyright/typeddicts_extra_items.toml
@@ -0,0 +1,65 @@
+conformant = "Pass"
+conformance_automated = "Pass"
+errors_diff = """
+"""
+output = """
+typeddicts_extra_items.py:15:45 - error: Type "dict[str, str | int]" is not assignable to declared type "Movie"
+ "Literal[1982]" is not assignable to "bool" (reportAssignmentType)
+typeddicts_extra_items.py:22:55 - error: Type "dict[str, str | int]" is not assignable to declared type "MovieFunctional"
+ "Literal[1982]" is not assignable to "bool" (reportAssignmentType)
+typeddicts_extra_items.py:39:54 - error: Type "dict[str, str | None]" is not assignable to declared type "InheritedMovie"
+ "None" is not assignable to "int" (reportAssignmentType)
+typeddicts_extra_items.py:49:35 - error: Expected "closed" parameter to have a value of True or False (reportGeneralTypeIssues)
+typeddicts_extra_items.py:67:7 - error: Base class "ClosedBase" is a TypedDict that limits the type of extra items to type "Never"
+ Cannot add item "age" (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:73:7 - error: Base class "ExtraItemsBase" is a TypedDict that limits the type of extra items to type "int"
+ Cannot add item "age" because it must be NotRequired (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:91:7 - error: Base class "MovieA" is a TypedDict that limits the type of extra items to type "Never"
+ Cannot add item "age" (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:94:7 - error: Base class "MovieB" is a TypedDict that limits the type of extra items to type "Never"
+ Cannot add item "age" (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:111:50 - error: "Required" is not allowed in this context (reportInvalidTypeForm)
+typeddicts_extra_items.py:114:57 - error: "NotRequired" is not allowed in this context (reportInvalidTypeForm)
+typeddicts_extra_items.py:125:9 - error: Could not delete item in TypedDict
+ "name" is a required key and cannot be deleted (reportGeneralTypeIssues)
+typeddicts_extra_items.py:140:48 - error: No parameter named "year" (reportCallIssue)
+typeddicts_extra_items.py:171:7 - error: Base class "Parent" is a TypedDict that limits the type of extra items to type "int | None"
+ Cannot add item "extra_items" with type "int" (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:181:7 - error: Base class "MovieBase2" is a TypedDict that limits the type of extra items to type "int | None"
+ Cannot add item "year" because it must be NotRequired (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:184:7 - error: Base class "MovieBase2" is a TypedDict that limits the type of extra items to type "int | None"
+ Cannot add item "year" with type "int" (reportIncompatibleVariableOverride)
+typeddicts_extra_items.py:206:22 - error: Type "MovieDetails" is not assignable to declared type "MovieBase2"
+ Type of "year" is incompatible with type of "extra_items" in "MovieBase2"
+ Type "int" is not assignable to type "int | None"
+ "int" is not assignable to "None" (reportAssignmentType)
+typeddicts_extra_items.py:213:22 - error: Type "MovieWithYear2" is not assignable to declared type "MovieBase2"
+ "year" is not required in "MovieBase2" (reportAssignmentType)
+typeddicts_extra_items.py:233:19 - error: Type "MovieDetails5" is not assignable to declared type "MovieSI"
+ Type of "actors" is incompatible with type of "extra_items" in "MovieSI"
+ Type "list[str]" is not assignable to type "str | int"
+ "list[str]" is not assignable to "str"
+ "list[str]" is not assignable to "int" (reportAssignmentType)
+typeddicts_extra_items.py:247:13 - error: Type "MovieExtraStr" is not assignable to declared type "MovieExtraInt"
+ Type of "extra_items" is incompatible with type of "extra_items" in "MovieExtraStr"
+ "str" is not assignable to "int" (reportAssignmentType)
+typeddicts_extra_items.py:248:13 - error: Type "MovieExtraInt" is not assignable to declared type "MovieExtraStr"
+ Type of "extra_items" is incompatible with type of "extra_items" in "MovieExtraInt"
+ "int" is not assignable to "str" (reportAssignmentType)
+typeddicts_extra_items.py:259:14 - error: Type "MovieNotClosed" is not assignable to declared type "MovieExtraInt"
+ Type of "extra_items" is incompatible with type of "extra_items" in "MovieNotClosed"
+ "object" is not assignable to "int" (reportAssignmentType)
+typeddicts_extra_items.py:269:1 - error: No overloads for "__init__" match the provided arguments
+ Argument types: (Literal['No Country for Old Men'], Literal[2007]) (reportCallIssue)
+typeddicts_extra_items.py:276:52 - error: Argument of type "Literal['English']" cannot be assigned to parameter "language" of type "int" in function "__init__"
+ "Literal['English']" is not assignable to "int" (reportArgumentType)
+typeddicts_extra_items.py:284:1 - error: No overloads for "__init__" match the provided arguments
+ Argument types: (Literal['No Country for Old Men'], Literal[2007]) (reportCallIssue)
+typeddicts_extra_items.py:294:34 - error: Type "MovieExtraInt" is not assignable to declared type "Mapping[str, int]"
+ "Mapping[str, str | int]" is not assignable to "Mapping[str, int]"
+ Type parameter "_VT_co@Mapping" is covariant, but "str | int" is not a subtype of "int"
+ Type "str | int" is not assignable to type "int"
+ "str" is not assignable to "int" (reportAssignmentType)
+typeddicts_extra_items.py:343:25 - error: Type "dict[str, int]" is not assignable to declared type "IntDict"
+ "dict[str, int]" is not assignable to "IntDict" (reportAssignmentType)
+"""
diff --git a/conformance/results/results.html b/conformance/results/results.html
index cce50c1e..40ce04d0 100644
--- a/conformance/results/results.html
+++ b/conformance/results/results.html
@@ -162,13 +162,13 @@
Python Type System Conformance Test Results
2.0sec
@@ -819,6 +819,12 @@ Python Type System Conformance Test Results
| Partial Does not reject methods within TypedDict class. Does not report when metaclass is provided. Does not report when other keyword argument is provided. Does not support generic TypedDict class. |
Pass |
+| typeddicts_extra_items |
+Unsupported Not supported. |
+Pass |
+Unsupported Not supported. |
+Unsupported Not supported. |
+
| typeddicts_final |
Pass |
Pass |
diff --git a/conformance/results/zuban/typeddicts_extra_items.toml b/conformance/results/zuban/typeddicts_extra_items.toml
new file mode 100644
index 00000000..0cc9199f
--- /dev/null
+++ b/conformance/results/zuban/typeddicts_extra_items.toml
@@ -0,0 +1,139 @@
+conformant = "Unsupported"
+notes = """
+Not supported.
+"""
+conformance_automated = "Fail"
+errors_diff = """
+Line 22: Expected 1 errors
+Line 181: Expected 1 errors
+Line 184: Expected 1 errors
+Line 206: Expected 1 errors
+Line 213: Expected 1 errors
+Line 233: Expected 1 errors
+Line 247: Expected 1 errors
+Line 248: Expected 1 errors
+Line 259: Expected 1 errors
+Lines 91, 92: Expected error (tag 'MovieC')
+Lines 94, 95: Expected error (tag 'MovieD')
+Line 11: Unexpected errors ['typeddicts_extra_items.py:11: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 14: Unexpected errors ['typeddicts_extra_items.py:14: error: Extra key "novel_adaptation" for TypedDict "Movie"']
+Line 19: Unexpected errors ['typeddicts_extra_items.py:19: error: Unexpected keyword argument "extra_items" for "TypedDict"']
+Line 29: Unexpected errors ['typeddicts_extra_items.py:29: error: Expression is of type "Any", not "bool"', 'typeddicts_extra_items.py:29: error: TypedDict "Movie" has no key "novel_adaptation"']
+Line 33: Unexpected errors ['typeddicts_extra_items.py:33: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 40: Unexpected errors ['typeddicts_extra_items.py:40: error: Extra key "other_extra_key" for TypedDict "InheritedMovie"']
+Line 55: Unexpected errors ['typeddicts_extra_items.py:55: error: Unexpected keyword argument "closed" for TypedDict']
+Line 64: Unexpected errors ['typeddicts_extra_items.py:64: error: Unexpected keyword argument "closed" for TypedDict']
+Line 70: Unexpected errors ['typeddicts_extra_items.py:70: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 82: Unexpected errors ['typeddicts_extra_items.py:82: error: Unexpected keyword argument "closed" for TypedDict']
+Line 88: Unexpected errors ['typeddicts_extra_items.py:88: error: Unexpected keyword argument "closed" for TypedDict']
+Line 100: Unexpected errors ['typeddicts_extra_items.py:100: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 103: Unexpected errors ['typeddicts_extra_items.py:103: error: Unexpected keyword argument "closed" for TypedDict']
+Line 106: Unexpected errors ['typeddicts_extra_items.py:106: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 121: Unexpected errors ['typeddicts_extra_items.py:121: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 126: Unexpected errors ['typeddicts_extra_items.py:126: error: TypedDict "MovieEI" has no key "year"']
+Line 134: Unexpected errors ['typeddicts_extra_items.py:134: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 141: Unexpected errors ['typeddicts_extra_items.py:141: error: Unexpected keyword argument "year" for "unpack_extra"']
+Line 146: Unexpected errors ['typeddicts_extra_items.py:146: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 149: Unexpected errors ['typeddicts_extra_items.py:149: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 152: Unexpected errors ['typeddicts_extra_items.py:152: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 162: Unexpected errors ['typeddicts_extra_items.py:162: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 168: Unexpected errors ['typeddicts_extra_items.py:168: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 178: Unexpected errors ['typeddicts_extra_items.py:178: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 201: Unexpected errors ['typeddicts_extra_items.py:201: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 208: Unexpected errors ['typeddicts_extra_items.py:208: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 219: Unexpected errors ['typeddicts_extra_items.py:219: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 222: Unexpected errors ['typeddicts_extra_items.py:222: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 226: Unexpected errors ['typeddicts_extra_items.py:226: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 239: Unexpected errors ['typeddicts_extra_items.py:239: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 242: Unexpected errors ['typeddicts_extra_items.py:242: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 245: Unexpected errors ['typeddicts_extra_items.py:245: error: Extra key "year" for TypedDict "MovieExtraInt"']
+Line 246: Unexpected errors ['typeddicts_extra_items.py:246: error: Extra key "description" for TypedDict "MovieExtraStr"']
+Line 257: Unexpected errors ['typeddicts_extra_items.py:257: error: Extra key "year" for TypedDict "MovieExtraInt"']
+Line 271: Unexpected errors ['typeddicts_extra_items.py:271: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 275: Unexpected errors ['typeddicts_extra_items.py:275: error: Extra key "year" for TypedDict "ExtraMovie"']
+Line 280: Unexpected errors ['typeddicts_extra_items.py:280: error: Unexpected keyword argument "closed" for TypedDict']
+Line 290: Unexpected errors ['typeddicts_extra_items.py:290: error: Extra key "summary" for TypedDict "MovieExtraStr"']
+Line 291: Unexpected errors ['typeddicts_extra_items.py:291: error: Incompatible types in assignment (expression has type "MovieExtraStr", variable has type "Mapping[str, str]")']
+Line 293: Unexpected errors ['typeddicts_extra_items.py:293: error: Extra key "year" for TypedDict "MovieExtraInt"']
+Line 295: Unexpected errors ['typeddicts_extra_items.py:295: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int | str]")']
+Line 301: Unexpected errors ['typeddicts_extra_items.py:301: error: Expression is of type "list[tuple[str, object]]", not "list[tuple[str, int | str]]"']
+Line 302: Unexpected errors ['typeddicts_extra_items.py:302: error: Expression is of type "list[object]", not "list[int | str]"']
+Line 310: Unexpected errors ['typeddicts_extra_items.py:310: error: Unexpected keyword argument "extra_items" for TypedDict']
+Line 317: Unexpected errors ['typeddicts_extra_items.py:317: error: Incompatible types in assignment (expression has type "IntDict", variable has type "dict[str, int]")']
+Line 320: Unexpected errors ['typeddicts_extra_items.py:320: error: Extra key "bar" for TypedDict "IntDictWithNum"']
+Line 321: Unexpected errors ['typeddicts_extra_items.py:321: error: Incompatible types in assignment (expression has type "IntDictWithNum", variable has type "dict[str, int]")']
+Line 328: Unexpected errors ['typeddicts_extra_items.py:328: error: "IntDictWithNum" has no attribute "clear"']
+Line 330: Unexpected errors ['typeddicts_extra_items.py:330: error: Expression is of type "Any", not "tuple[str, int]"', 'typeddicts_extra_items.py:330: error: "IntDictWithNum" has no attribute "popitem"']
+Line 333: Unexpected errors ['typeddicts_extra_items.py:333: error: TypedDict key must be a string literal; expected one of ("num")']
+Line 334: Unexpected errors ['typeddicts_extra_items.py:334: error: Expected TypedDict key to be string literal']
+"""
+output = """
+typeddicts_extra_items.py:11: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:14: error: Extra key "novel_adaptation" for TypedDict "Movie"
+typeddicts_extra_items.py:15: error: Extra key "year" for TypedDict "Movie"
+typeddicts_extra_items.py:19: error: Unexpected keyword argument "extra_items" for "TypedDict"
+typeddicts_extra_items.py:29: error: Expression is of type "Any", not "bool"
+typeddicts_extra_items.py:29: error: TypedDict "Movie" has no key "novel_adaptation"
+typeddicts_extra_items.py:33: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:39: error: Incompatible types (expression has type "None", TypedDict item "year" has type "int")
+typeddicts_extra_items.py:40: error: Extra key "other_extra_key" for TypedDict "InheritedMovie"
+typeddicts_extra_items.py:49: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:55: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:64: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:67: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:70: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:73: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:82: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:88: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:100: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:103: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:106: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:111: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:114: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:121: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:125: error: Key "name" of TypedDict "MovieEI" cannot be deleted
+typeddicts_extra_items.py:126: error: TypedDict "MovieEI" has no key "year"
+typeddicts_extra_items.py:134: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:140: error: Unexpected keyword argument "year" for "unpack_no_extra"
+typeddicts_extra_items.py:141: error: Unexpected keyword argument "year" for "unpack_extra"
+typeddicts_extra_items.py:146: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:149: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:152: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:162: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:168: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:171: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:178: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:201: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:208: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:219: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:222: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:226: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:239: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:242: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:245: error: Extra key "year" for TypedDict "MovieExtraInt"
+typeddicts_extra_items.py:246: error: Extra key "description" for TypedDict "MovieExtraStr"
+typeddicts_extra_items.py:257: error: Extra key "year" for TypedDict "MovieExtraInt"
+typeddicts_extra_items.py:269: error: Extra key "year" for TypedDict "NonClosedMovie"
+typeddicts_extra_items.py:271: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:275: error: Extra key "year" for TypedDict "ExtraMovie"
+typeddicts_extra_items.py:276: error: Extra key "language" for TypedDict "ExtraMovie"
+typeddicts_extra_items.py:280: error: Unexpected keyword argument "closed" for TypedDict
+typeddicts_extra_items.py:284: error: Extra key "year" for TypedDict "ClosedMovie"
+typeddicts_extra_items.py:290: error: Extra key "summary" for TypedDict "MovieExtraStr"
+typeddicts_extra_items.py:291: error: Incompatible types in assignment (expression has type "MovieExtraStr", variable has type "Mapping[str, str]")
+typeddicts_extra_items.py:293: error: Extra key "year" for TypedDict "MovieExtraInt"
+typeddicts_extra_items.py:294: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int]")
+typeddicts_extra_items.py:295: error: Incompatible types in assignment (expression has type "MovieExtraInt", variable has type "Mapping[str, int | str]")
+typeddicts_extra_items.py:301: error: Expression is of type "list[tuple[str, object]]", not "list[tuple[str, int | str]]"
+typeddicts_extra_items.py:302: error: Expression is of type "list[object]", not "list[int | str]"
+typeddicts_extra_items.py:310: error: Unexpected keyword argument "extra_items" for TypedDict
+typeddicts_extra_items.py:317: error: Incompatible types in assignment (expression has type "IntDict", variable has type "dict[str, int]")
+typeddicts_extra_items.py:320: error: Extra key "bar" for TypedDict "IntDictWithNum"
+typeddicts_extra_items.py:321: error: Incompatible types in assignment (expression has type "IntDictWithNum", variable has type "dict[str, int]")
+typeddicts_extra_items.py:328: error: "IntDictWithNum" has no attribute "clear"
+typeddicts_extra_items.py:330: error: Expression is of type "Any", not "tuple[str, int]"
+typeddicts_extra_items.py:330: error: "IntDictWithNum" has no attribute "popitem"
+typeddicts_extra_items.py:333: error: TypedDict key must be a string literal; expected one of ("num")
+typeddicts_extra_items.py:334: error: Expected TypedDict key to be string literal
+typeddicts_extra_items.py:343: error: Incompatible types in assignment (expression has type "dict[str, int]", variable has type "IntDict")
+"""
diff --git a/conformance/results/zuban/version.toml b/conformance/results/zuban/version.toml
index 1f4c294b..d3d2104d 100644
--- a/conformance/results/zuban/version.toml
+++ b/conformance/results/zuban/version.toml
@@ -1,2 +1,2 @@
version = "zuban 0.0.19"
-test_duration = 0.35
+test_duration = 0.32
diff --git a/conformance/tests/typeddicts_extra_items.py b/conformance/tests/typeddicts_extra_items.py
new file mode 100644
index 00000000..b0a797ee
--- /dev/null
+++ b/conformance/tests/typeddicts_extra_items.py
@@ -0,0 +1,347 @@
+# pyright: enableExperimentalFeatures=true
+from collections.abc import Mapping
+from typing_extensions import ReadOnly, TypedDict, Unpack
+from typing import assert_type, Required, NotRequired, Never
+
+
+# > For a TypedDict type that specifies
+# > ``extra_items``, during construction, the value type of each unknown item
+# is expected to be non-required and assignable to the ``extra_items`` argument.
+
+class Movie(TypedDict, extra_items=bool):
+ name: str
+
+a: Movie = {"name": "Blade Runner", "novel_adaptation": True} # OK
+b: Movie = {"name": "Blade Runner", "year": 1982} # E: 'int' is not assignable to 'bool'
+
+# > The alternative inline syntax is also supported::
+
+MovieFunctional = TypedDict("MovieFunctional", {"name": str}, extra_items=bool)
+
+c: MovieFunctional = {"name": "Blade Runner", "novel_adaptation": True} # OK
+d: MovieFunctional = {"name": "Blade Runner", "year": 1982} # E: 'int' is not assignable to 'bool'
+
+# > Accessing extra items is allowed. Type checkers must infer their value type from
+# > the ``extra_items`` argument
+
+def movie_keys(movie: Movie) -> None:
+ assert_type(movie["name"], str)
+ assert_type(movie["novel_adaptation"], bool)
+
+# > ``extra_items`` is inherited through subclassing
+
+class MovieBase(TypedDict, extra_items=ReadOnly[int | None]):
+ name: str
+
+class InheritedMovie(MovieBase):
+ year: int
+
+e: InheritedMovie = {"name": "Blade Runner", "year": None} # E: 'None' is incompatible with 'int'
+f: InheritedMovie = {
+ "name": "Blade Runner",
+ "year": 1982,
+ "other_extra_key": None,
+} # OK
+
+# > Similar to ``total``, only a literal ``True`` or ``False`` is supported as the
+# > value of the ``closed`` argument. Type checkers should reject any non-literal value.
+
+class IllegalTD(TypedDict, closed=42 == 42): # E: Argument to "closed" must be a literal True or False
+ name: str
+
+# > Passing ``closed=False`` explicitly requests the default TypedDict behavior,
+# > where arbitrary other keys may be present and subclasses may add arbitrary items.
+
+class BaseTD(TypedDict, closed=False):
+ name: str
+
+class ChildTD(BaseTD): # OK
+ age: int
+
+# > It is a type checker error to pass ``closed=False`` if a superclass has
+# > ``closed=True`` or sets ``extra_items``.
+
+class ClosedBase(TypedDict, closed=True):
+ name: str
+
+class IllegalChild1(ClosedBase, closed=False): # E: Cannot set 'closed=False' when superclass is 'closed=True'
+ age: int
+
+class ExtraItemsBase(TypedDict, extra_items=int):
+ name: str
+
+class IllegalChild2(ExtraItemsBase, closed=False): # E: Cannot set 'closed=False' when superclass has 'extra_items'
+ age: int
+
+# > If ``closed`` is not provided, the behavior is inherited from the superclass.
+# > If the superclass is TypedDict itself or the superclass does not have ``closed=True``
+# > or the ``extra_items`` parameter, the previous TypedDict behavior is preserved:
+# > arbitrary extra items are allowed. If the superclass has ``closed=True``, the
+# > child class is also closed.
+
+class BaseMovie(TypedDict, closed=True):
+ name: str
+
+class MovieA(BaseMovie): # OK, still closed
+ pass
+
+class MovieB(BaseMovie, closed=True): # OK, but redundant
+ pass
+
+class MovieC(MovieA): # E[MovieC]
+ age: int # E[MovieC]: "MovieC" is a closed TypedDict; extra key "age" not allowed
+
+class MovieD(MovieB): # E[MovieD]
+ age: int # E[MovieD]: "MovieD" is a closed TypedDict; extra key "age" not allowed
+
+# > It is possible to use ``closed=True`` when subclassing if the ``extra_items``
+# > argument is a read-only type.
+
+class MovieES(TypedDict, extra_items=ReadOnly[str]):
+ pass
+
+class MovieClosed(MovieES, closed=True): # OK
+ pass
+
+class MovieNever(MovieES, extra_items=Never): # OK, but 'closed=True' is preferred
+ pass
+
+# > It is an error to use ``Required[]`` or ``NotRequired[]`` with ``extra_items``.
+
+class IllegalExtraItemsTD(TypedDict, extra_items=Required[int]): # E: 'extra_items' value cannot be 'Required[...]'
+ name: str
+
+class AnotherIllegalExtraItemsTD(TypedDict, extra_items=NotRequired[int]): # E: 'extra_items' value cannot be 'NotRequired[...]'
+ name: str
+
+# > The extra items are non-required, regardless of the totality of the
+# > TypedDict. Operations that are available to ``NotRequired`` items should also be available to the
+# > extra items.
+
+class MovieEI(TypedDict, extra_items=int):
+ name: str
+
+def del_items(movie: MovieEI) -> None:
+ del movie["name"] # E: The value type of 'name' is 'Required[str]'
+ del movie["year"] # OK: The value type of 'year' is 'NotRequired[int]'
+
+# > For type checking purposes, ``Unpack[SomeTypedDict]`` with extra items should be
+# > treated as its equivalent in regular parameters.
+
+class MovieNoExtra(TypedDict):
+ name: str
+
+class MovieExtra(TypedDict, extra_items=int):
+ name: str
+
+def unpack_no_extra(**kwargs: Unpack[MovieNoExtra]) -> None: ...
+def unpack_extra(**kwargs: Unpack[MovieExtra]) -> None: ...
+
+unpack_no_extra(name="No Country for Old Men", year=2007) # E: Unrecognized item
+unpack_extra(name="No Country for Old Men", year=2007) # OK
+
+# > Notably, if the TypedDict type specifies ``extra_items`` to be read-only,
+# > subclasses of the TypedDict type may redeclare ``extra_items``.
+
+class ReadOnlyBase(TypedDict, extra_items=ReadOnly[int]):
+ pass
+
+class ReadOnlyChild(ReadOnlyBase, extra_items=ReadOnly[bool]): # OK
+ pass
+
+class MutableChild(ReadOnlyBase, extra_items=int): # OK
+ pass
+
+# > Because a non-closed TypedDict type implicitly allows non-required extra items
+# > of value type ``ReadOnly[object]``, its subclass can override the
+# > ``extra_items`` argument with more specific types.
+
+class NonClosedBase(TypedDict):
+ name: str
+
+class SpecificExtraItems(NonClosedBase, extra_items=bytes): # OK
+ year: int
+
+# > First, it is not allowed to change the value of ``extra_items`` in a subclass
+# > unless it is declared to be ``ReadOnly`` in the superclass.
+
+class Parent(TypedDict, extra_items=int | None):
+ pass
+
+class Child(Parent, extra_items=int): # E: Cannot change 'extra_items' type unless it is 'ReadOnly' in the superclass
+ pass
+
+# > Second, ``extra_items=T`` effectively defines the value type of any unnamed
+# > items accepted to the TypedDict and marks them as non-required. Thus, the above
+# > restriction applies to any additional items defined in a subclass.
+
+class MovieBase2(TypedDict, extra_items=int | None):
+ name: str
+
+class MovieRequiredYear(MovieBase2): # E: Required key 'year' is not known to 'MovieBase'
+ year: int | None
+
+class MovieNotRequiredYear(MovieBase2): # E: 'int | None' is not consistent with 'int'
+ year: NotRequired[int]
+
+class MovieWithYear(MovieBase): # OK
+ year: NotRequired[int | None]
+
+# > Let ``S`` be the set of keys of the explicitly defined items on a TypedDict
+# > type. If it specifies ``extra_items=T``, the TypedDict type is considered to
+# > have an infinite set of items that all satisfy the following conditions.
+# > - If ``extra_items`` is read-only:
+# > - The key's value type is :term:`assignable` to ``T``.
+# > - The key is not in ``S``.
+# > - If ``extra_items`` is not read-only:
+# > - The key is non-required.
+# > - The key's value type is :term:`consistent` with ``T``.
+# > - The key is not in ``S``.
+
+class MovieDetails(TypedDict, extra_items=int | None):
+ name: str
+ year: NotRequired[int]
+
+details2: MovieDetails = {"name": "Kill Bill Vol. 1", "year": 2003}
+movie2: MovieBase2 = details2 # E: While 'int' is not consistent with 'int | None'
+
+class MovieWithYear2(TypedDict, extra_items=int | None):
+ name: str
+ year: int | None
+
+details3: MovieWithYear2 = {"name": "Kill Bill Vol. 1", "year": 2003}
+movie3: MovieBase2 = details3 # E:'year' is not required in 'Movie', but it is required in 'MovieWithYear2'
+
+# > When ``extra_items`` is specified to be read-only on a TypedDict type, it is
+# > possible for an item to have a :term:`narrower ` type than the
+# > ``extra_items`` argument.
+
+class MovieSI(TypedDict, extra_items=ReadOnly[str | int]):
+ name: str
+
+class MovieDetails4(TypedDict, extra_items=int):
+ name: str
+ year: NotRequired[int]
+
+class MovieDetails5(TypedDict, extra_items=int):
+ name: str
+ actors: list[str]
+
+details4: MovieDetails4 = {"name": "Kill Bill Vol. 2", "year": 2004}
+details5: MovieDetails5 = {"name": "Kill Bill Vol. 2", "actors": ["Uma Thurman"]}
+movie4: MovieSI = details4 # OK. 'int' is assignable to 'str | int'.
+movie5: MovieSI = details5 # E: 'list[str]' is not assignable to 'str | int'.
+
+# > ``extra_items`` as a pseudo-item follows the same rules that other items have,
+# > so when both TypedDicts types specify ``extra_items``, this check is naturally
+# > enforced.
+
+class MovieExtraInt(TypedDict, extra_items=int):
+ name: str
+
+class MovieExtraStr(TypedDict, extra_items=str):
+ name: str
+
+extra_int: MovieExtraInt = {"name": "No Country for Old Men", "year": 2007}
+extra_str: MovieExtraStr = {"name": "No Country for Old Men", "description": ""}
+extra_int = extra_str # E: 'str' is not assignable to extra items type 'int'
+extra_str = extra_int # E: 'int' is not assignable to extra items type 'str'
+
+# > A non-closed TypedDict type implicitly allows non-required extra keys of value
+# > type ``ReadOnly[object]``. Applying the assignability rules between this type
+# > and a closed TypedDict type is allowed.
+
+class MovieNotClosed(TypedDict):
+ name: str
+
+extra_int2: MovieExtraInt = {"name": "No Country for Old Men", "year": 2007}
+not_closed: MovieNotClosed = {"name": "No Country for Old Men"}
+extra_int2 = not_closed # E: 'extra_items=ReadOnly[object]' implicitly on 'MovieNotClosed' is not assignable to with 'extra_items=int'
+not_closed = extra_int2 # OK
+
+# > TypedDicts that allow extra items of type ``T`` also allow arbitrary keyword
+# > arguments of this type when constructed by calling the class object.
+
+class NonClosedMovie(TypedDict):
+ name: str
+
+NonClosedMovie(name="No Country for Old Men") # OK
+NonClosedMovie(name="No Country for Old Men", year=2007) # E: Unrecognized item
+
+class ExtraMovie(TypedDict, extra_items=int):
+ name: str
+
+ExtraMovie(name="No Country for Old Men") # OK
+ExtraMovie(name="No Country for Old Men", year=2007) # OK
+ExtraMovie(name="No Country for Old Men", language="English") # E: Wrong type for extra item 'language'
+
+# This implies 'extra_items=Never',
+# so extra keyword arguments would produce an error
+class ClosedMovie(TypedDict, closed=True):
+ name: str
+
+ClosedMovie(name="No Country for Old Men") # OK
+ClosedMovie(name="No Country for Old Men", year=2007) # E: Extra items not allowed
+
+# > A TypedDict type is :term:`assignable` to a type of the form ``Mapping[str, VT]``
+# > when all value types of the items in the TypedDict
+# > are assignable to ``VT``.
+
+extra_str3: MovieExtraStr = {"name": "Blade Runner", "summary": ""}
+str_mapping: Mapping[str, str] = extra_str3 # OK
+
+extra_int3: MovieExtraInt = {"name": "Blade Runner", "year": 1982}
+int_mapping: Mapping[str, int] = extra_int3 # E: 'int | str' is not assignable with 'int'
+int_str_mapping: Mapping[str, int | str] = extra_int3 # OK
+
+# > Type checkers should infer the precise signatures of ``values()`` and ``items()``
+# > on such TypedDict types.
+
+def foo(movie: MovieExtraInt) -> None:
+ assert_type(list(movie.items()), list[tuple[str, int | str]])
+ assert_type(list(movie.values()), list[int | str])
+
+# > The TypedDict type is :term:`assignable` to ``dict[str, VT]`` if all
+# > items on the TypedDict type satisfy the following conditions:
+# > - The value type of the item is :term:`consistent` with ``VT``.
+# > - The item is not read-only.
+# > - The item is not required.
+
+class IntDict(TypedDict, extra_items=int):
+ pass
+
+class IntDictWithNum(IntDict):
+ num: NotRequired[int]
+
+def clear_intdict(x: IntDict) -> None:
+ v: dict[str, int] = x # OK
+ v.clear() # OK
+
+not_required_num_dict: IntDictWithNum = {"num": 1, "bar": 2}
+regular_dict: dict[str, int] = not_required_num_dict # OK
+clear_intdict(not_required_num_dict) # OK
+
+# > In this case, methods that are previously unavailable on a TypedDict are allowed,
+# > with signatures matching ``dict[str, VT]``
+# > (e.g.: ``__setitem__(self, key: str, value: VT) -> None``).
+
+not_required_num_dict.clear() # OK
+
+assert_type(not_required_num_dict.popitem(), tuple[str, int])
+
+def nrnd(not_required_num_dict: IntDictWithNum, key: str):
+ not_required_num_dict[key] = 42 # OK
+ del not_required_num_dict[key] # OK
+
+# > ``dict[str, VT]`` is not assignable to a TypedDict type,
+# > because such dict can be a subtype of dict.
+
+class CustomDict(dict[str, int]):
+ pass
+
+def might_not_be(might_not_be_a_builtin_dict: dict[str, int]):
+ int_dict: IntDict = might_not_be_a_builtin_dict # E
+ print(int_dict)
+
+not_a_builtin_dict = CustomDict({"num": 1})
+might_not_be(not_a_builtin_dict)
diff --git a/docs/spec/typeddict.rst b/docs/spec/typeddict.rst
index 4cbeedba..153fd0b7 100644
--- a/docs/spec/typeddict.rst
+++ b/docs/spec/typeddict.rst
@@ -285,6 +285,8 @@ refers to a dictionary object does not need to be supported, to simplify
implementation.
+.. _typeddict-assignability:
+
Assignability
^^^^^^^^^^^^^
@@ -410,6 +412,8 @@ Discussion:
f(b)
+.. _typeddict-operations:
+
Supported and Unsupported Operations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -841,3 +845,553 @@ As discussed in the section :ref:`unpack-kwargs`, an unpacked ``TypedDict`` can
kwargs["key1"] = 3 # Type check error: key1 is readonly
fn: Function = impl # Accepted by type checker: function signatures are identical
+
+Extra Items and Closed TypedDicts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+(Originally specified in :pep:`728`.)
+
+This section discusses the ``extra_items`` and ``closed`` class parameters.
+
+If ``extra_items`` is specified, extra items are treated as :ref:`non-required
+`
+items matching the ``extra_items`` argument, whose keys are allowed when
+determining :ref:`supported and unsupported operations
+`.
+
+The ``extra_items`` Class Parameter
+-----------------------------------
+
+By default ``extra_items`` is unset. For a TypedDict type that specifies
+``extra_items``, during construction, the value type of each unknown item
+is expected to be non-required and assignable to the ``extra_items`` argument.
+For example::
+
+ class Movie(TypedDict, extra_items=bool):
+ name: str
+
+ a: Movie = {"name": "Blade Runner", "novel_adaptation": True} # OK
+ b: Movie = {
+ "name": "Blade Runner",
+ "year": 1982, # Not OK. 'int' is not assignable to 'bool'
+ }
+
+Here, ``extra_items=bool`` specifies that items other than ``'name'``
+have a value type of ``bool`` and are non-required.
+
+The alternative inline syntax is also supported::
+
+ Movie = TypedDict("Movie", {"name": str}, extra_items=bool)
+
+Accessing extra items is allowed. Type checkers must infer their value type from
+the ``extra_items`` argument::
+
+ def f(movie: Movie) -> None:
+ reveal_type(movie["name"]) # Revealed type is 'str'
+ reveal_type(movie["novel_adaptation"]) # Revealed type is 'bool'
+
+``extra_items`` is inherited through subclassing::
+
+ class MovieBase(TypedDict, extra_items=ReadOnly[int | None]):
+ name: str
+
+ class Movie(MovieBase):
+ year: int
+
+ a: Movie = {"name": "Blade Runner", "year": None} # Not OK. 'None' is incompatible with 'int'
+ b: Movie = {
+ "name": "Blade Runner",
+ "year": 1982,
+ "other_extra_key": None,
+ } # OK
+
+Here, ``'year'`` in ``a`` is an extra key defined on ``Movie`` whose value type
+is ``int``. ``'other_extra_key'`` in ``b`` is another extra key whose value type
+must be assignable to the value of ``extra_items`` defined on ``MovieBase``.
+
+.. _typed-dict-closed:
+
+The ``closed`` Class Parameter
+------------------------------
+
+When neither ``extra_items`` nor ``closed=True`` is specified, ``closed=False``
+is assumed. The TypedDict should allow non-required extra items of value type
+``ReadOnly[object]`` during inheritance or assignability checks, to
+preserve the default TypedDict behavior. Extra keys included in TypedDict
+object construction should still be caught, as mentioned :ref:`above `.
+
+When ``closed=True`` is set, no extra items are allowed. This is equivalent to
+``extra_items=Never``, because there can't be a value type that is assignable to
+:class:`~typing.Never`. It is a runtime error to use the ``closed`` and
+``extra_items`` parameters in the same TypedDict definition.
+
+Similar to ``total``, only a literal ``True`` or ``False`` is supported as the
+value of the ``closed`` argument. Type checkers should reject any non-literal value.
+
+Passing ``closed=False`` explicitly requests the default TypedDict behavior,
+where arbitrary other keys may be present and subclasses may add arbitrary items.
+It is a type checker error to pass ``closed=False`` if a superclass has
+``closed=True`` or sets ``extra_items``.
+
+If ``closed`` is not provided, the behavior is inherited from the superclass.
+If the superclass is TypedDict itself or the superclass does not have ``closed=True``
+or the ``extra_items`` parameter, the previous TypedDict behavior is preserved:
+arbitrary extra items are allowed. If the superclass has ``closed=True``, the
+child class is also closed::
+
+ class BaseMovie(TypedDict, closed=True):
+ name: str
+
+ class MovieA(BaseMovie): # OK, still closed
+ pass
+
+ class MovieB(BaseMovie, closed=True): # OK, but redundant
+ pass
+
+ class MovieC(BaseMovie, closed=False): # Type checker error
+ pass
+
+As a consequence of ``closed=True`` being equivalent to ``extra_items=Never``,
+the same rules that apply to ``extra_items=Never`` also apply to
+``closed=True``. While they both have the same effect, ``closed=True`` is
+preferred over ``extra_items=Never``.
+
+It is possible to use ``closed=True`` when subclassing if the ``extra_items``
+argument is a read-only type::
+
+ class Movie(TypedDict, extra_items=ReadOnly[str]):
+ pass
+
+ class MovieClosed(Movie, closed=True): # OK
+ pass
+
+ class MovieNever(Movie, extra_items=Never): # OK, but 'closed=True' is preferred
+ pass
+
+This will be further discussed in
+:ref:`a later section `.
+
+``closed`` is also supported with the functional syntax::
+
+ Movie = TypedDict("Movie", {"name": str}, closed=True)
+
+Interaction with Totality
+-------------------------
+
+It is an error to use ``Required[]`` or ``NotRequired[]`` with ``extra_items``.
+``total=False`` and ``total=True`` have no effect on ``extra_items`` itself.
+
+The extra items are non-required, regardless of the `totality
+`__ of the
+TypedDict. :ref:`Operations `
+that are available to ``NotRequired`` items should also be available to the
+extra items::
+
+ class Movie(TypedDict, extra_items=int):
+ name: str
+
+ def f(movie: Movie) -> None:
+ del movie["name"] # Not OK. The value type of 'name' is 'Required[int]'
+ del movie["year"] # OK. The value type of 'year' is 'NotRequired[int]'
+
+Interaction with ``Unpack``
+---------------------------
+
+For type checking purposes, ``Unpack[SomeTypedDict]`` with extra items should be
+treated as its equivalent in regular parameters, and the existing rules for
+function parameters still apply::
+
+ class MovieNoExtra(TypedDict):
+ name: str
+
+ class MovieExtra(TypedDict, extra_items=int):
+ name: str
+
+ def f(**kwargs: Unpack[MovieNoExtra]) -> None: ...
+ def g(**kwargs: Unpack[MovieExtra]) -> None: ...
+
+ # Should be equivalent to:
+ def f(*, name: str) -> None: ...
+ def g(*, name: str, **kwargs: int) -> None: ...
+
+ f(name="No Country for Old Men", year=2007) # Not OK. Unrecognized item
+ g(name="No Country for Old Men", year=2007) # OK
+
+Interaction with Read-only Items
+--------------------------------
+
+When the ``extra_items`` argument is annotated with the ``ReadOnly[]``
+:term:`type qualifier`, the extra items on the TypedDict have the
+properties of read-only items. This interacts with inheritance rules specified
+in :ref:`Read-only Items `.
+
+Notably, if the TypedDict type specifies ``extra_items`` to be read-only,
+subclasses of the TypedDict type may redeclare ``extra_items``.
+
+Because a non-closed TypedDict type implicitly allows non-required extra items
+of value type ``ReadOnly[object]``, its subclass can override the
+``extra_items`` argument with more specific types.
+
+More details are discussed in the later sections.
+
+Inheritance
+-----------
+
+``extra_items`` is inherited in a similar way as a regular ``key: value_type``
+item. As with the other keys, the `inheritance rules
+`__
+and :ref:`Read-only Items ` inheritance rules apply.
+
+We need to reinterpret these rules to define how ``extra_items`` interacts with
+them.
+
+ * Changing a field type of a parent TypedDict class in a subclass is not allowed.
+
+First, it is not allowed to change the value of ``extra_items`` in a subclass
+unless it is declared to be ``ReadOnly`` in the superclass::
+
+ class Parent(TypedDict, extra_items=int | None):
+ pass
+
+ class Child(Parent, extra_items=int): # Not OK. Like any other TypedDict item, extra_items's type cannot be changed
+ pass
+
+Second, ``extra_items=T`` effectively defines the value type of any unnamed
+items accepted to the TypedDict and marks them as non-required. Thus, the above
+restriction applies to any additional items defined in a subclass. For each item
+added in a subclass, all of the following conditions should apply:
+
+.. _pep728-inheritance-read-only:
+
+- If ``extra_items`` is read-only
+
+ - The item can be either required or non-required
+
+ - The item's value type is :term:`assignable` to ``T``
+
+- If ``extra_items`` is not read-only
+
+ - The item is non-required
+
+ - The item's value type is :term:`consistent` with ``T``
+
+- If ``extra_items`` is not overridden, the subclass inherits it as-is.
+
+For example::
+
+ class MovieBase(TypedDict, extra_items=int | None):
+ name: str
+
+ class MovieRequiredYear(MovieBase): # Not OK. Required key 'year' is not known to 'MovieBase'
+ year: int | None
+
+ class MovieNotRequiredYear(MovieBase): # Not OK. 'int | None' is not consistent with 'int'
+ year: NotRequired[int]
+
+ class MovieWithYear(MovieBase): # OK
+ year: NotRequired[int | None]
+
+ class BookBase(TypedDict, extra_items=ReadOnly[int | str]):
+ title: str
+
+ class Book(BookBase, extra_items=str): # OK
+ year: int # OK
+
+An important side effect of the inheritance rules is that we can define a
+TypedDict type that disallows additional items::
+
+ class MovieClosed(TypedDict, extra_items=Never):
+ name: str
+
+Here, passing the value :class:`~typing.Never` to ``extra_items`` specifies that
+there can be no other keys in ``MovieFinal`` other than the known ones.
+Because of its potential common use, there is a preferred alternative::
+
+ class MovieClosed(TypedDict, closed=True):
+ name: str
+
+where we implicitly assume that ``extra_items=Never``.
+
+Assignability
+-------------
+
+Let ``S`` be the set of keys of the explicitly defined items on a TypedDict
+type. If it specifies ``extra_items=T``, the TypedDict type is considered to
+have an infinite set of items that all satisfy the following conditions.
+
+- If ``extra_items`` is read-only:
+
+ - The key's value type is :term:`assignable` to ``T``.
+
+ - The key is not in ``S``.
+
+- If ``extra_items`` is not read-only:
+
+ - The key is non-required.
+
+ - The key's value type is :term:`consistent` with ``T``.
+
+ - The key is not in ``S``.
+
+For type checking purposes, let ``extra_items`` be a non-required pseudo-item
+when checking for assignability according to rules defined in the
+:ref:`Read-only Items ` section, with a new rule added in bold
+text as follows:
+
+ A TypedDict type ``B`` is :term:`assignable` to a TypedDict type
+ ``A`` if ``B`` is :term:`structurally ` assignable to
+ ``A``. This is true if and only if all of the following are satisfied:
+
+ * **[If no key with the same name can be found in ``B``, the 'extra_items'
+ argument is considered the value type of the corresponding key.]**
+
+ * For each item in ``A``, ``B`` has the corresponding key, unless the item in
+ ``A`` is read-only, not required, and of top value type
+ (``ReadOnly[NotRequired[object]]``).
+
+ * For each item in ``A``, if ``B`` has the corresponding key, the corresponding
+ value type in ``B`` is assignable to the value type in ``A``.
+
+ * For each non-read-only item in ``A``, its value type is assignable to the
+ corresponding value type in ``B``, and the corresponding key is not read-only
+ in ``B``.
+
+ * For each required key in ``A``, the corresponding key is required in ``B``.
+
+ * For each non-required key in ``A``, if the item is not read-only in ``A``,
+ the corresponding key is not required in ``B``.
+
+The following examples illustrate these checks in action.
+
+``extra_items`` puts various restrictions on additional items for assignability
+checks::
+
+ class Movie(TypedDict, extra_items=int | None):
+ name: str
+
+ class MovieDetails(TypedDict, extra_items=int | None):
+ name: str
+ year: NotRequired[int]
+
+ details: MovieDetails = {"name": "Kill Bill Vol. 1", "year": 2003}
+ movie: Movie = details # Not OK. While 'int' is assignable to 'int | None',
+ # 'int | None' is not assignable to 'int'
+
+ class MovieWithYear(TypedDict, extra_items=int | None):
+ name: str
+ year: int | None
+
+ details: MovieWithYear = {"name": "Kill Bill Vol. 1", "year": 2003}
+ movie: Movie = details # Not OK. 'year' is not required in 'Movie',
+ # but it is required in 'MovieWithYear'
+
+where ``MovieWithYear`` (B) is not assignable to ``Movie`` (A)
+according to this rule:
+
+ * For each non-required key in ``A``, if the item is not read-only in ``A``,
+ the corresponding key is not required in ``B``.
+
+When ``extra_items`` is specified to be read-only on a TypedDict type, it is
+possible for an item to have a :term:`narrower ` type than the
+``extra_items`` argument::
+
+ class Movie(TypedDict, extra_items=ReadOnly[str | int]):
+ name: str
+
+ class MovieDetails(TypedDict, extra_items=int):
+ name: str
+ year: NotRequired[int]
+
+ details: MovieDetails = {"name": "Kill Bill Vol. 2", "year": 2004}
+ movie: Movie = details # OK. 'int' is assignable to 'str | int'.
+
+This behaves the same way as if ``year: ReadOnly[str | int]`` is an item
+explicitly defined in ``Movie``.
+
+``extra_items`` as a pseudo-item follows the same rules that other items have,
+so when both TypedDicts types specify ``extra_items``, this check is naturally
+enforced::
+
+ class MovieExtraInt(TypedDict, extra_items=int):
+ name: str
+
+ class MovieExtraStr(TypedDict, extra_items=str):
+ name: str
+
+ extra_int: MovieExtraInt = {"name": "No Country for Old Men", "year": 2007}
+ extra_str: MovieExtraStr = {"name": "No Country for Old Men", "description": ""}
+ extra_int = extra_str # Not OK. 'str' is not assignable to extra items type 'int'
+ extra_str = extra_int # Not OK. 'int' is not assignable to extra items type 'str'
+
+A non-closed TypedDict type implicitly allows non-required extra keys of value
+type ``ReadOnly[object]``. Applying the assignability rules between this type
+and a closed TypedDict type is allowed::
+
+ class MovieNotClosed(TypedDict):
+ name: str
+
+ extra_int: MovieExtraInt = {"name": "No Country for Old Men", "year": 2007}
+ not_closed: MovieNotClosed = {"name": "No Country for Old Men"}
+ extra_int = not_closed # Not OK.
+ # 'extra_items=ReadOnly[object]' implicitly on 'MovieNotClosed'
+ # is not assignable to with 'extra_items=int'
+ not_closed = extra_int # OK
+
+Interaction with Constructors
+-----------------------------
+
+TypedDicts that allow extra items of type ``T`` also allow arbitrary keyword
+arguments of this type when constructed by calling the class object::
+
+ class NonClosedMovie(TypedDict):
+ name: str
+
+ NonClosedMovie(name="No Country for Old Men") # OK
+ NonClosedMovie(name="No Country for Old Men", year=2007) # Not OK. Unrecognized item
+
+ class ExtraMovie(TypedDict, extra_items=int):
+ name: str
+
+ ExtraMovie(name="No Country for Old Men") # OK
+ ExtraMovie(name="No Country for Old Men", year=2007) # OK
+ ExtraMovie(
+ name="No Country for Old Men",
+ language="English",
+ ) # Not OK. Wrong type for extra item 'language'
+
+ # This implies 'extra_items=Never',
+ # so extra keyword arguments would produce an error
+ class ClosedMovie(TypedDict, closed=True):
+ name: str
+
+ ClosedMovie(name="No Country for Old Men") # OK
+ ClosedMovie(
+ name="No Country for Old Men",
+ year=2007,
+ ) # Not OK. Extra items not allowed
+
+Supported and Unsupported Operations
+------------------------------------
+
+This statement from :ref:`above ` still holds true.
+
+ Operations with arbitrary str keys (instead of string literals or other
+ expressions with known string values) should generally be rejected.
+
+Operations that already apply to ``NotRequired`` items should generally also
+apply to extra items, following the same rationale from :ref:`above `:
+
+ The exact type checking rules are up to each type checker to decide. In some
+ cases potentially unsafe operations may be accepted if the alternative is to
+ generate false positive errors for idiomatic code.
+
+Some operations, including indexed accesses and assignments with arbitrary str keys,
+may be allowed due to the TypedDict being :term:`assignable` to
+``Mapping[str, VT]`` or ``dict[str, VT]``. The two following sections will expand
+on that.
+
+Interaction with Mapping[str, VT]
+---------------------------------
+
+A TypedDict type is :term:`assignable` to a type of the form ``Mapping[str, VT]``
+when all value types of the items in the TypedDict
+are assignable to ``VT``. For the purpose of this rule, a
+TypedDict that does not have ``extra_items=`` or ``closed=`` set is considered
+to have an item with a value of type ``ReadOnly[object]``. This extends the
+general rule for :ref:`TypedDict assignability `.
+
+For example::
+
+ class MovieExtraStr(TypedDict, extra_items=str):
+ name: str
+
+ extra_str: MovieExtraStr = {"name": "Blade Runner", "summary": ""}
+ str_mapping: Mapping[str, str] = extra_str # OK
+
+ class MovieExtraInt(TypedDict, extra_items=int):
+ name: str
+
+ extra_int: MovieExtraInt = {"name": "Blade Runner", "year": 1982}
+ int_mapping: Mapping[str, int] = extra_int # Not OK. 'int | str' is not assignable with 'int'
+ int_str_mapping: Mapping[str, int | str] = extra_int # OK
+
+Type checkers should infer the precise signatures of ``values()`` and ``items()``
+on such TypedDict types::
+
+ def foo(movie: MovieExtraInt) -> None:
+ reveal_type(movie.items()) # Revealed type is 'dict_items[str, str | int]'
+ reveal_type(movie.values()) # Revealed type is 'dict_values[str, str | int]'
+
+By extension of this assignability rule, type checkers may allow indexed accesses
+with arbitrary str keys when ``extra_items`` or ``closed=True`` is specified.
+For example::
+
+ def bar(movie: MovieExtraInt, key: str) -> None:
+ reveal_type(movie[key]) # Revealed type is 'str | int'
+
+.. _pep728-type-narrowing:
+
+Defining the type narrowing behavior for TypedDict is out-of-scope for this spec.
+This leaves flexibility for a type checker to be more/less restrictive about
+indexed accesses with arbitrary str keys. For example, a type checker may opt
+for more restriction by requiring an explicit ``'x' in d`` check.
+
+Interaction with dict[str, VT]
+------------------------------
+
+Because the presence of ``extra_items`` on a closed TypedDict type
+prohibits additional required keys in its :term:`structural`
+:term:`subtypes `, we can determine if the TypedDict type and
+its structural subtypes will ever have any required key during static analysis.
+
+The TypedDict type is :term:`assignable` to ``dict[str, VT]`` if all
+items on the TypedDict type satisfy the following conditions:
+
+- The value type of the item is :term:`consistent` with ``VT``.
+
+- The item is not read-only.
+
+- The item is not required.
+
+For example::
+
+ class IntDict(TypedDict, extra_items=int):
+ pass
+
+ class IntDictWithNum(IntDict):
+ num: NotRequired[int]
+
+ def f(x: IntDict) -> None:
+ v: dict[str, int] = x # OK
+ v.clear() # OK
+
+ not_required_num_dict: IntDictWithNum = {"num": 1, "bar": 2}
+ regular_dict: dict[str, int] = not_required_num_dict # OK
+ f(not_required_num_dict) # OK
+
+In this case, methods that are previously unavailable on a TypedDict are allowed,
+with signatures matching ``dict[str, VT]``
+(e.g.: ``__setitem__(self, key: str, value: VT) -> None``)::
+
+ not_required_num_dict.clear() # OK
+
+ reveal_type(not_required_num_dict.popitem()) # OK. Revealed type is 'tuple[str, int]'
+
+ def f(not_required_num_dict: IntDictWithNum, key: str):
+ not_required_num_dict[key] = 42 # OK
+ del not_required_num_dict[key] # OK
+
+:ref:`Notes on indexed accesses ` from the previous section
+still apply.
+
+``dict[str, VT]`` is not assignable to a TypedDict type,
+because such dict can be a subtype of dict::
+
+ class CustomDict(dict[str, int]):
+ pass
+
+ def f(might_not_be_a_builtin_dict: dict[str, int]):
+ int_dict: IntDict = might_not_be_a_builtin_dict # Not OK
+
+ not_a_builtin_dict = CustomDict({"num": 1})
+ f(not_a_builtin_dict)
|---|