PEP 728: TypedDict with Typed Extra Items

Here are a couple of additional ideas to throw into the mix.


The first idea involves the use of a method declaration within a TypedDict.

Currently, TypedDict definitions don’t allow any method declarations. We could specify that a __closed__ method can be declared that returns the type of the allowed ‘extra’ attributes.

class Point(TypedDict):
    x: float
    y: float
    def __closed__(self) -> Never: ...

This idea has the benefit of not affecting backward compatibility.

The downsides are that it’s probably not what most Python developers would expect. It’s also not clear how this would work with the functional form of TypedDict.


The second idea involves the use of a new parameter to the TypedDict constructor named closed. If set to True, the TypedDict would be considered “closed” in that type checkers should assume that no additional items are allowed. If a user wants to allow additional items of a specific type, they would additionally include an __extra__: <type> attribute declaration. If no __extra__ is present but closed is set to True, it acts as though an implicit __extra__: Never is present.

class Point1(TypedDict, closed=True):
    x: float
    y: float

class Point2(TypedDict, closed=True):
    x: float
    y: float
    __extra__: int

I think this construct feels pretty natural — especially in the common case where the user simply wants to specify that no other items can be present. It also preserves backward compatibility and works with the functional form. It could also be made to work with a potential future inlined version (by special-casing __extra__ in the inlined version).

In the (extremely unlikely) event that you want to create a closed TypedDict with a key named __extra__, you could do so through inheritance.

# Create a non-closed TypedDict that includes `__extra__` item
class TDWithExtra(TypedDict):
    x: float
    y: float
    __extra__: float

# Create a closed version of the above
class ClosedTDWithExtra1(TDWithExtra, closed=True):
    ...

# Or a closed version with extra items
class ClosedTDWithExtra2(TDWithExtra, closed=True):
    __extra__: int
4 Likes