Skip to content

Anonymous and inline declaration of TypedDict types #9884

Closed
@jetzhou

Description

@jetzhou

Feature
Currently, TypedDict must be declared and used as so:

MyDict = TypedDict('MyDict', {'foo': int, 'bar': bool})
def fn() -> MyDict:
    pass

In many situations, the type doesn't actually get re-used outside the context of this one local function, so a much more concise declaration would be:

def fn() -> TypedDict({'foo': int, 'bar': bool}):
    pass

or alternatively:

def fn() -> TypedDict(foo=int, bar=bool):
    pass

This syntax makes the TypedDict definition both anonymous and inline, which are two separate features I guess, even though they are pretty much hand in hand. Both are desirable in situations where the return type isn't re-used in multiple places so there is no need for the separate MyDict definition.

Pitch

I've read through #985 and python/typing#28. Both issues had a little bit of discussion on anonymous TypedDict and dismissed the feature as not being useful enough.

In my case, we run a GraphQL server and many of our mutation types return dictionaries/JSON objects with the shape {'ok': bool, 'error': str, 'item': <ItemType>}. These objects have no relevance outside of where their mutation function is defined, so it is extremely verbose and pointless to type:

ReturnType = TypedDict('ReturnedType', {'ok': bool, 'error': str, 'item': <ItemType>})
def mutation() -> ReturnType:
    return {'ok', True, 'error', '', 'item': <item>}

When everything can be succinctly expressed as:

def mutation() -> TypedDict({'ok': bool, 'error': str, 'item': <ItemType>}):
    return {'ok', True, 'error', '', 'item': <item>}

The simplified syntax has better readability and loses none of the type safety that's achieved with the type hints.

Outside of my use cases, I can also imagine that inline anonymous TypedDict can be pretty useful when they are used in a nested fashion, something like:

MyType = TypedDict({
    'foo': int,
    'bar': TypedDict({
        'baz': int,
    })
})

Happy to provide more context on the use case that I have or to come up with more use cases. If this seems like a worthy direction to pursue, I would definitely love to dig into implementation and figure out what needs to be done to make this happen.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions