
I've thought more about James' suggestion and I agree with it with one significant change, namely about the behaviour when a class subclasses both TypedMapping and TypedDict. Here is my revised proposal. # Specification ```python class Request(TypedMapping, total=False): some_field: string | None request: Request = { "some_field": "foo" } request2: Request = {} # fine because total=False request["some_field"] = None # error del request["some_field"] # error ``` TypedMapping is a structural type that mirrors TypedDict except for: 1) instances need not be subclasses of dict; 2) no mutate methods will be generated 3) subclasses can narrow field types (consequence of 2) Rules for 3 mirror Protocols. ## Multiple inheritance and TypedDict A type that inherits from a TypedMapping subclass and from TypedDict (either directly or indirectly): 4) is the structural intersection of its parents, or invalid if no such intersection exists 5) instances must be a dict subclass 6) adds mutate methods only for fields it explicitly (re)declares ```python class A(TypedMapping): field1: int field2: str class B(A, TypedDict): field1: int b: B = { "field1": 5, "field2": "value" } b["field1"] = 6 # Fine, mutate methods added in definition of B b["field2"] = "value2" # Error, field2 mutator not declared ``` The alternative here would be: 6b) adds mutate methods for all fields declared in superclasses (unless redeclared in the body) I think this unnecessarily restricts usage though, and doesn't match how inheritance works in other cases (e.g. total=False and total=True do not affect fields not specified in the class body). --- Alice Bloomberg