
I would like to propose adding a boolean `readonly` parameter to TypedDict, which would remove all mutate operations from the resulting type. # Specification ```python class Request(TypedDict, total=False, readonly=True): some_field: string | None request: Request = { "some_field": "foo" } request["some_field"] = None # error del request["some_field"] # error ``` I suggest making it illegal to have a subclass that does not have the same readonly value as its superclass(es), as on the one hand, it would be natural to expect the following to be equivalent: ```python # Declare some_field explicitly class MutableRequest(TypedDict, total=False): some_field: string | None # Inherit some_field from Request class MutableRequest(Request, readonly=False): pass ```python But on the other hand, by analogy with total we would expect only the fields explicitly declared on the class to be affected by the readonly flag. I'm not aware of a usecase for the latter, and the ambiguity between the two possible interpretations would probably be a source of issues. # Use case We are making increasing use of TypedDict to type hint code that uses dictionaries to hold requests to and responses from services (both client and server side). However, we run into problems whenever any constraint is loosened, e.g. passing data from a response where a field is guaranteed to a request where it is optional: ```python class Response(TypedDict): some_field: string class Request(TypedDict, total=False): some_field: string | None class Server1: def fetch_data() -> Response: ... class Server2: def accept_data(request: Request): ... def my_code(server1: Server1, server2: Server2): data: Response = server1.fetch_data() server2.accept_data(data) # error: Response and Request are incompatible ```python This last line is not type-safe, as there are mutation operations on Request that aren't valid on Response. If we could remove those mutation operations from the Request type, then it would be a valid subtype of Response. This problem seems quite common, e.g. https://github.com/python/mypy/pull/12142. I am thinking of making a PEP (Pablo Galindo has agreed to sponsor). What does everyone think? Is the proposal sound and implementable? --- Alice Bloomberg