Allow StrEnum members to be used as keys in TypedDict

Copy of Allow StrEnum members to be used as keys in TypedDict · python/typing · Discussion #1721 · GitHub (someone mentioned this where most discussions happen now)

Making TypedDict work with keys of other types like StrEnum would require a change to the TypedDict specification [this pyright comment]

from enum import StrEnum
from typing import Final, TypedDict

A = 'a'

class Foo(StrEnum):
    a = 'a'

class Bar(TypedDict):
    a: int

bar: Bar = {A: 1}  # Ok
bar2: Bar = {Foo.a: 1}  # Error: Expression of type "dict[Foo, int]" cannot be assigned to declared type "Bar"
bar3: Final[Bar] = {Foo.a: 1}  # As above
bar[Foo.a]  # Error: Could not access item in TypedDict;  "Literal[Foo.a]" is not a string literal

This seems to be an XY problem. What is the original problem?

I can’t reproduce the first one passing. TypedDicts are supposed to be defined with string literals -this was exactly the intention behind PEP589.

Which typechecker are you using?

str_enum.py

from enum import StrEnum
from typing import TypedDict

A = 'a'


class Bar(TypedDict):
    a: int

bar: Bar = {A: 1}  # Not OK

mypy str_enum.py
str_enum.py:12: error: Expected TypedDict key to be string literal  [misc]
Found 1 error in 1 file (checked 1 source file)

It works if you mark the variable as Final (in which case mypy treats its type as Literal["a"]):

from enum import StrEnum
from typing import Final, TypedDict

A: Final = 'a'


class Bar(TypedDict):
    a: int

bar: Bar = {A: 1}  # OK
2 Likes

Maybe the example is overly contrived (taken from the pyright issue).

For us this has arisen naturally when we have converted untyped dicts to typed dicts. The existing code often used a string enum to keep track of valid keys and thus have many instances of data_dict[Keys.key_1]. You could argue that it would be best to replace the Keys.key_1 usages by the literal string after the conversion, but I’m not fully convinced that has much value by itself.

Retiring the Keys enum does remove the need to keep the typed dict and enum in sync, but sometimes the keys are used outside a direct typed dict context. (Eg.: a function which expects a key which later is used to index the typed dict).

Besides “is it bad practice to use string enums to index typed dicts”, I’m struggling to understand the rationale for not allowing this. String enum values surely are intended to be final (even if it might technically be possible to mutate them runtime).

Quoting “layday” from the pyright issue:

StrEnum’s raison d’etre is to avoid having to access value


I can’t reproduce the first one passing. TypedDicts are supposed to be defined with string literals. … Which typechecker are you using?

pyright. It claims A is a Literal[‘a’] though. (I miiight have some settings on which affect this :thinking:)

2 Likes