# PEP 705: Read-only TypedDict items

**URL:** <https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867>\
**Category:** PEPs\
**Tags:** typing\
**Created:** [November 4, 2023, 8:28am UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867 "2023-11-04T08:28:36Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [November 4, 2023, 8:28am UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/1 "2023-11-04T08:28:36Z")

</div>

[PEP 705](https://peps.python.org/pep-0705/) proposes supporting read-only items in TypedDicts, allowing functions that access but do not modify data in TypedDicts (e.g. service APIs) to be annotated to accept a wide range of compatible types.

The pyright playground has support for this extension, if anyone wants to experiment; [instructions for using it can be found here](https://discuss.python.org/t/pep-705-typeddict-read-only-and-other-keys/36457/11).

Feedback appreciated!

---

<div class="post-metadata">

**Author:** ![davidfstr](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/davidfstr/32/6944_2.png) [@davidfstr](https://discuss.python.org/u/davidfstr)\
**Post date:** [November 4, 2023, 2:23pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/2 "2023-11-04T14:23:56Z")

</div>

Looks great! Some feedback:

- PEP readers who are not typing experts may appreciate adding a paragraph like the following to the end of §“Abstract”, so that they don’t need to read further: (I added a similar paragraph in PEP 655 based on feedback received then.)

> This PEP makes no Python grammar changes. Correct usage of read-only keys of TypedDicts is intended to be enforced only by static type checkers and need not be enforced by Python itself at runtime.

- §“Motivation” is quite clear. 👍 [§“Updating nested dicts”](https://peps.python.org/pep-0705/#updating-nested-dicts) in particular is not something I considered when thinking about `ReadOnly[]` before.

- I’d recommend adding a section to §“Specification” explaining how `get_type_hints()` treats `ReadOnly[]`, similar to [the callouts in PEP 655](https://peps.python.org/pep-0655/#runtime-behavior). For completeness you might consider mentioning the altered behavior of `get_origin()`, and `get_args()` as well.

- Nit: Suggest adding the following changes in bold:

> Suggest **ed** changes to the [`typing`](https://docs.python.org/3/library/typing.html#module-typing) module **documentation** , in line with current practice:

- Nit: In “Individual items can be excluded from mutate operations […]” the phrase “mutate operations” feels both overly technical and vague to me. Suggested wordsmithing to be less technical:

> Individual items can be prevented from being changed by marking then as ReadOnly, allowing them only to be read.

- Nit: For “pyright 1.1.332 fully implements this proposal.” suggest linking to the changelog or commit from pyright that indicates that it added ReadOnly support.

- Nit: In the sentence “It would be reasonable for someone familiar with `frozen`, […]” it’s not clear what `frozen` is referring to. There are no other uses of the word “frozen” in the PEP. Did you mean `readonly` instead?

- There are multiple locations in this PEP that include a `Never`-typed TypedDict item. (See example below.) It’s not clear to me what that even means. I suppose I don’t have specific feedback on this construction other than I find it confusing.

```python
class B(TypedDict):
  foo: NotRequired[Never]

```

- In §“Rejected alternatives” maybe it would be worth talking about why the existing `Final[]` qualifier couldn’t be used in place of introducing a new `ReadOnly[]` qualifier? I think this was discussed before but I don’t remember what was said.

- (I did not review the formal rules in §“Type Consistency”, due to lack of energy/time)

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [November 4, 2023, 5:32pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/3 "2023-11-04T17:32:39Z")

</div>

Thank you for the feedback! I will look to get this all improved/clarified in the PEP. In the meantime, to some of the questions you asked:

- `Never` is [typing.Never](https://docs.python.org/3/library/typing.html#typing.Never). Nothing will ever match this type, so if you use it to specify a value in a dictionary, that value must be absent.
- `frozen` is a parameter on [dataclasses](https://docs.python.org/3/library/dataclasses.html), also used to similar effect in third party libraries
- I mention why these aren’t “final” in the opening of the rationale section. (I will still add it to the rejected alternatives section!)

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [November 28, 2023, 8:10pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/4 "2023-11-28T20:10:06Z")

</div>

@davidfstr Thanks again for the feedback! PR to address it has now merged.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [November 29, 2023, 8:10pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/5 "2023-11-29T20:10:53Z")

</div>

`typing.ReadOnly` is now available in [typing-extensions 4.9.0-rc1](https://github.com/python/typing_extensions/releases/tag/4.9.0rc1) (thanks @Jelle!)

---

<div class="post-metadata">

**Author:** ![bluetech](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/bluetech/32/8859_2.png) [@bluetech](https://discuss.python.org/u/bluetech)\
**Post date:** [November 30, 2023, 8:13am UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/6 "2023-11-30T08:13:21Z")

</div>

I’m in favor of this PEP.

### Pure functions motivation

The “Pure functions” motivation section contains a very specific problem this solves, but I think the premier motivation is: code which shouldn’t mutate, should not be able to mutate. This is similar to the [Principle of Least Authority](https://en.wikipedia.org/wiki/Principle_of_least_privilege) from security, but I’m thinking about it from a maintainability angle: if a function takes `Mapping` I’m much more relaxed about it than if it takes `dict`. And `ReadOnly` brings this feature to `TypedDict`.

From my experience in TypeScript, my code is littered with `readonly` everywhere, and I often wish `readonly` was the default and a `mutable` keyword was used instead, but obviously that’s not possible here.

### `Final` rejected alternative

In the [Reusing the `Final` annotation](https://peps.python.org/pep-0705/#reusing-the-final-annotation) rejected alternative section, the PEP says “[Final] is documented as preventing redefinition in subclasses […] This does not fit with the intended use of `ReadOnly`”. Just to make sure I understand, can you explain this a bit more or give an example?

I’m not sure if “subclasses” refers to actual overriding (i.e. subclassing the TypedDict) or to structural subtyping.

### TypedDict Literals

TypeScript has a feature where a dict (“object” in TS) literal is inferred as the TypedDict type, e.g.

```ts
const foo = {"a": 1};
# Type of foo is `{"a": number}`

```

Unfortunately, neither mypy nor pyright do this currently (even if the variable is `Final`), but I _think_ it should be possible as an improvement.

Such dynamically-inferred TypedDict creates a problem that there is no way to specify `ReadOnly`. In TypeScript, they fixed this with a new syntax:

```ts
const foo = {"a": 1} as const;
# Type of foo is `{readonly "a": 1}`

```

I don’t think this should have an impact on the PEP but I thought it’s interesting to mention.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 2, 2023, 11:53am UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/7 "2023-12-02T11:53:37Z")

</div>

> [@bluetech](#):
>
> In the [Reusing the `Final` annotation](https://peps.python.org/pep-0705/#reusing-the-final-annotation) rejected alternative section, the PEP says “[Final] is documented as preventing redefinition in subclasses […] This does not fit with the intended use of `ReadOnly`”. Just to make sure I understand, can you explain this a bit more or give an example?
> 
> I’m not sure if “subclasses” refers to actual overriding (i.e. subclassing the TypedDict) or to structural subtyping.

The problem is that the Final annotation PEP, PEP-591, only discusses traditional classes, not structural subtypes. The Protocol and TypedDict types are not mentioned at all, though they were introduced in the same version of Python.

PEP-544 draws a distinction between _explicit subclasses_ and _implicit subtypes_, and then goes on to drop the words “explicit” and “implicit”, using subclass to refer to what is in the MRO, and subtype to refer to what is structurally compatible. However, that doesn’t necessarily imply that PEP-591 must be only talking about explicit subclasses, since it doesn’t seem to be considering structural subtyping at all. (And sadly, PEP-544 doesn’t mention the Final annotation at all either.)

I took the view in PEP-705 that subclassing for structural types should be considered equivalent to asking the type-checker to validate structural subtyping (though I’ll note that this isn’t entirely coherent since Protocols also get implementation inheritance). This has come up explicitly in [Required/NotRequired and inheritance · python/typing · Discussion #1516 · GitHub](https://github.com/python/typing/discussions/1516), and pyright’s main maintainer seems to be taking this view as well, at least for TypedDicts. This allows us to infer what `Final` should mean for structural typing: it should prevent redefinition in structural subtypes.

If that line of reasoning is not convincing, we can take a look at what type-checkers currently think of this ambiguity, in the context of Protocols; let’s try some code:

```python
class A(Protocol):
  x: Final[int | None]

class B(Protocol):
  x: int

def b_to_a(b: B) -> A:
  return b

```

Passing this to mypy, we get:

```plaintext
error: Protocol member cannot be final

```

On the other hand, passing it to pyright, we get:

```plaintext
Expression of type "B" cannot be assigned to return type "A"
    "B" is incompatible with protocol "A"
      "x" is marked Final in protocol

```

So either Final shouldn’t be used in a structural type at all (mypy’s view), or it should not be removable in a structural subtype (pyright’s view).

This is not compatible with how we want ReadOnly to behave; the equivalent example should be legal in any type-checker:

```auto
class A(TypedDict):
  x: ReadOnly[int | None]

class B(TypedDict):
  x: int

def b_to_a(b: B) -> A:
  return b

```

This makes sense: a Final property _should never change once set_. That’s the intent of the annotation. But we can’t (and don’t want to) prevent a ReadOnly item changing in a TypedDict _instance_; we only want to prevent it _being changed through this structural type definition_, because it has incomplete information about what the actual type constraints on the item are, so cannot safely make a change.

I hope this has made things clearer and not muddier!

---

<div class="post-metadata">

**Author:** ![bluetech](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/bluetech/32/8859_2.png) [@bluetech](https://discuss.python.org/u/bluetech)\
**Post date:** [December 2, 2023, 8:33pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/8 "2023-12-02T20:33:45Z")

</div>

Thanks! To restate my understanding: `Final` has a specific meaning of the item being set once and not changing ever. This is important for example if `Final` is ever to be used for thread safety checking like it is in Java. `ReadOnly` however is more of a restriction on the “view” of the dict, so that we can remove some limitations on `TypedDict` sub-typing that mutability makes unsound. `ReadOnly` has no reason to require total “finality” of the dict instance item.

Speaking of threading, it might be useful to make it clear in the PEP (as a non-normative note) that `ReadOnly` does _not_ imply that `x` can not be mutated by another concurrent thread.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 3, 2023, 12:49pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/9 "2023-12-03T12:49:55Z")

</div>

> [@bluetech](#):
>
> it might be useful to make it clear in the PEP (as a non-normative note) that `ReadOnly` does _not_ imply that `x` can not be mutated by another concurrent thread.

I have the following text at the start of the Rationale section:

> This does not mean the items are immutable: a reference to the underlying dictionary could still exist with a different but compatible type in which those items have mutator operations.

I could add text like “This could be used, for instance, to update the item in a concurrent thread” if this helps cement the idea.

---

<div class="post-metadata">

**Author:** ![Jelle](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jelle/32/1049_2.png) [@Jelle](https://discuss.python.org/u/Jelle)\
**Post date:** [December 12, 2023, 9:05pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/10 "2023-12-12T21:05:55Z")

</div>

Overall I like this PEP and I look forward to being able to declare TypedDict as read-only. A few pieces of feedback:

- The runtime [implementation in typing-extensions](https://github.com/python/typing_extensions/blob/d6dc4f157e731b2475141aae0c2586ed0243b686/src/typing_extensions.py#L886) throws an error if a mutable key overrides a read-only one in a base class. I think I put that in because PEP 705 at the time specified this behavior, but the current version doesn’t seem to say this explicitly. I would like to drop this runtime check, as it’s generally better for the runtime to be permissive. For example, users may want to type ignore this particular error in some cases, or future extensions of TypedDict may come up that interfere with this check.
- I was sad to see that the `readonly=True` class argument is no longer in the PEP. I would personally want to default to declaring TypedDicts as read-only when possible, so I’d like to make that as easy as possible. The current iteration of the PEP would require repeating `ReadOnly[]` on every item, which is verbose.
- Relatedly, there is a lack of symmetry with the feature set available for stating whether keys are required. In that area, we can mark an individual key as Required or NotRequired and set the default for the whole TypedDict (`total=False`). But for marking a TypedDict read-only, the only option is to use `ReadOnly[]` to mark an individual key. For more flexibility, we could add a `read_only=True` class argument and a `Mutable[]` qualifier to mark individual keys as mutable in a TypedDict that defaults to read-only.

I’ll be out for the next few weeks, but wanted to get these ideas into the discussion.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 12, 2023, 10:29pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/11 "2023-12-12T22:29:26Z")

</div>

> [@Jelle](#):
>
> The runtime [implementation in typing-extensions](https://github.com/python/typing_extensions/blob/d6dc4f157e731b2475141aae0c2586ed0243b686/src/typing_extensions.py#L886) throws an error if a mutable key overrides a read-only one in a base class.

The other way up I think? But I am happy for this to be left to type-checkers either way.

---

<div class="post-metadata">

**Author:** ![Daverball](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/daverball/32/15931_2.png) [@Daverball](https://discuss.python.org/u/Daverball)\
**Post date:** [December 20, 2023, 12:55pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/12 "2023-12-20T12:55:22Z")

</div>

This came up in the discussion for creating a `Readable` type modifier: [Need a way to type-hint attributes that is compatible with duck-typing - #19 by randolf-scholz](https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137/19)

While for a `TypedDict` the distinction between a `Readable` and `ReadOnly` key barely matters, the distinction becomes more important when applied to a `Protocol` and nominal types.

Since according to the inheritance rules outlined in PEP 705 we are allowed to override a `ReadOnly` key with a writeable `key` it might be better to call the modifier `Readable` to ensure future consistency, if/when we want to extend the type modifier to work with additional types.

That being said, I do think the name `ReadOnly` better conveys the promise that this key will never be written to inside a function that uses it, so I understand why it is a more attractive name for the modifier, but it would also be a shame if we reject a future PEP that defines a `Readable` modifier that is distinct from `ReadOnly` based on the fact that this PEP was accepted with `ReadOnly` meaning `Readable`.

There is some precedent for the distinction between `Readable` and `ReadOnly` with the `Buffer` protocol placeholders in typeshed, where we have `ReadableBuffer` and `ReadOnlyBuffer`. These were introduced as part of an earlier version of PEP 688, which initially aimed to include mutability as part of the `Buffer` protocol.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 20, 2023, 2:21pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/13 "2023-12-20T14:21:20Z")

</div>

> [@Daverball](#):
>
> While for a `TypedDict` the distinction between a `Readable` and `ReadOnly` key barely matters,

I don’t agree with this; I think the distinction is relevant even for structural subtyping.

> [@Daverball](#):
>
> it might be better to call the modifier `Readable`

I’m happy to consider this. I’d like to do it on the basis of what is the best name for what you are calling “Readable”, though, not whether there’s a distinction based on TypedDict vs Protocol vs base class.

Would love to hear what other people prefer of the two suggestions.

> [@Daverball](#):
>
> There is some precedent for the distinction between `Readable` and `ReadOnly` with the `Buffer` protocol placeholders in typeshed, where we have `ReadableBuffer` and `ReadOnlyBuffer`

This isn’t much of a precedent, is there anything else?

---

<div class="post-metadata">

**Author:** ![Daverball](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/daverball/32/15931_2.png) [@Daverball](https://discuss.python.org/u/Daverball)\
**Post date:** [December 20, 2023, 2:54pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/14 "2023-12-20T14:54:44Z")

</div>

> [@alicederyn](#):
>
> > [@Daverball](#):
> >
> > There is some precedent for the distinction between `Readable` and `ReadOnly` with the `Buffer` protocol placeholders in typeshed, where we have `ReadableBuffer` and `ReadOnlyBuffer`
> 
> This isn’t much of a precedent, is there anything else?

These aliases are used consistently across typeshed so I think at least as far as naming goes, this is a well established precedent. Whether or not the type system currently supports distinguishing between them is irrelevant for the naming discussion.

You can make the argument that the buffer terminology does not translate to attribute/key access, but I would disagree, I think it translates very well. I won’t deny however that it’s easy to use `ReadOnly` when you actually meant to use `Readable`. I have made that mistake before myself with the `Buffer` protocols and have to sometimes catch myself. Although this will be less of an issue when the type checker actually starts complaining about inconsistent use of `ReadbleBuffer` vs `ReadOnlyBuffer`.

I can’t really think of a better name than `Readable` meaning “this attribute/key is readable” without placing any further restrictions. The main confusion in naming occurs once you look at it from a receiving-perspective rather than a giving-perspective. Because on the receiving end you don’t care whether the key/value is `Readable` or `ReadOnly`, in either case a read is the only explicitly allowed operation, so it is in a sense read only, with the subtle distinction that with the former you are forbidden, because you weren’t told that you are allowed to write and in the latter you are explicitly forbidden from writing.

I’m not sure there’s a name that is completely unambiguous both from a receiving and giving perspective.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 20, 2023, 3:09pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/15 "2023-12-20T15:09:00Z")

</div>

I would normally refer to what you’re calling “readonly” as “immutable”, which is a lot clearer of a distinction. I may be missing nuance though?

---

<div class="post-metadata">

**Author:** ![Daverball](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/daverball/32/15931_2.png) [@Daverball](https://discuss.python.org/u/Daverball)\
**Post date:** [December 20, 2023, 3:23pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/16 "2023-12-20T15:23:32Z")

</div>

The problem with `Immutable` is that it’s ambiguous, does it mean we create an immutable reference to the value, so the value itself can never be modified (i.e. any attribute or method access that would modify the object’s internal state is forbidden), or does it mean it’s invalid to change where the reference points to? When I hear immutable in the context of Python I think of the former, not the latter.

In short `Immutable` is a modifier on the wrapped type, `ReadOnly`/`Readable` are modifiers on the type containing the attribute/key. You can’t use them for both.

If we ever wanted to introduce mutability of objects into the type system I think we would regret having already used that name. `ReadOnly` is actually closer to `Final` than `Immutable` in my book.

---

<div class="post-metadata">

**Author:** ![erictraut](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/erictraut/32/15190_2.png) [@erictraut](https://discuss.python.org/u/erictraut)\
**Post date:** [December 20, 2023, 4:22pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/17 "2023-12-20T16:22:10Z")

</div>

I think `ReadOnly` is the right term to use here and in the future. `Readable` doesn’t convey the right meaning. Let’s stick with `ReadOnly`.

---

<div class="post-metadata">

**Author:** ![Daverball](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/daverball/32/15931_2.png) [@Daverball](https://discuss.python.org/u/Daverball)\
**Post date:** [December 20, 2023, 4:57pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/18 "2023-12-20T16:57:32Z")

</div>

If the more lax definition of `ReadOnly` was the only type modifier we ever wanted then I would agree, even if the term doesn’t completely match what it says on the tin, we usually care and think more about types from a receiving position and there `ReadOnly` is a better descriptor, but if we ever wanted to be able to express the more strict meaning as well we now don’t really have a good term for that.

Although I guess we could always try to go with what PEP 724 proposed initially for `TypeGuard` and use `StrictReadOnly` \[1\] to mean it’s only compatible if the attribute/key is read-only for both types.

* * *

1. or `StrictlyReadOnly` if we feel strongly about proper grammar

---

<div class="post-metadata">

**Author:** ![randolf-scholz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/randolf-scholz/32/11123_2.png) [@randolf-scholz](https://discuss.python.org/u/randolf-scholz)\
**Post date:** [December 20, 2023, 10:12pm UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/19 "2023-12-20T22:12:34Z")

</div>

> [@Daverball](#):
>
> Since according to the inheritance rules outlined in PEP 705 we are allowed to override a `ReadOnly` key with a writeable `key` it might be better to call the modifier `Readable` to ensure future consistency, if/when we want to extend the type modifier to work with additional types.

I had a second look at this, and it seems to me now that in [my comment here](https://discuss.python.org/t/need-a-way-to-type-hint-attributes-that-is-compatible-with-duck-typing/41137/19), it may be more appropriate to translate `foo: ReadOnly[T]` to ` __setattr__ (self, name: Literal["foo"], val: Never) -> None` instead of ` __setattr__ (self, name: Literal["foo"], val: T) -> Never`.

This is compatible with the intended usage here (applying to ` __setitem__ ` instead of ` __setattr__ `) and allows for contravariant overriding so that subclasses can choose to make a `ReadOnly` mutable.

I think if one wants to forbid writing for subtypes entirely, then `Final[ReadOnly[T]]` would be the correct thing to do.

---

<div class="post-metadata">

**Author:** ![alicederyn](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alicederyn/32/10282_2.png) [@alicederyn](https://discuss.python.org/u/alicederyn)\
**Post date:** [December 21, 2023, 8:48am UTC](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867/20 "2023-12-21T08:48:19Z")

</div>

_edit_: removed a bit where I was confused which interpretation of “ReadOnly” you meant…

> [@randolf-scholz](#):
>
> `Final[ReadOnly[T]]`

Why not just `Final[T]`?

[Next page](https://discuss.python.org/t/pep-705-read-only-typeddict-items/37867.md?page=2)
