Skip to content

Feature request: Allow unpacking of type variable bound to typed dict #1399

Open

Description

@NeilGirdhar

I'd like to have a family of classes where overrides have additional parameters to various methods:

from typing import Generic, Unpack

from typing_extensions import TypedDict, TypeVar, override


class EmptyDict(TypedDict, total=True):
    pass


Extra = TypeVar('Extra', bound=TypedDict, default=EmptyDict)


class C(Generic[Extra]):
    def f(self, **kwargs: Unpack[Extra]) -> None:  # error: Expected TypedDict type argument for Unpack (reportGeneralTypeIssues)
        pass


class D(C):
    @override
    def f(self) -> None:  # error: Method "f" overrides class "C" in an incompatible manner
        pass


class HasName(TypedDict, total=True):
    name: str


class E(C[HasName]):
    @override
    def f(self, name: str) -> None:  # This doesn't work.
        print(name)



D().f()
E().f("a")

See @erictraut's instructive comment on the issue here.

Activity

  1. added
    topic: featureDiscussions about new features for Python's type annotations
    on May 3, 2023
  2. hmc-cs-mdrissi commented on May 3, 2023

    @hmc-cs-mdrissi

    This would be kwargs equivalent of being able to unpack TypeVarTuple. This would I think solve this request to be able to use Paramspec kwargs only.

    I have a couple small use cases where this would be nice although they mostly follow other issue of more flexibility with preserving just args/kwargs/similar manipulation.

  3. jaywonchung commented on Sep 8, 2023

    @jaywonchung

    I believe I hit this issue when I was trying to write a type stub for networkx (or nx).

    nx.Graph and its variants allow arbitrary attributes to be associated with nodes, edges, and graphs. For example, adding a node has signature (ref):

    class Graph:
        def add_node(self, node_for_adding, **attr): ...

    I was trying to do this:

    N = TypeVar("N")  # type for node ID
    A = TypeVar("A", bound=TypedDict)  # type for node attribute
    
    class Graph(Generic[N, A]):
        def add_node(self, node_for_adding: N, **attr: Unpack[A]) -> None: ...
  4. NeilGirdhar commented on Sep 9, 2023

    @NeilGirdhar
    Author

    Yup, perfect example.

  5. paveldedik commented on May 6, 2024

    @paveldedik

    Is there something I could help with to speed this up? Probably only possible way to halp is to draft a PEP?

    Anyway, it would be really useful for a framework I'm building - https://github.com/paveldedik/ludic/blob/main/ludic/base.py#L293-L308

    It seems I can already bound a subclass of a TypedDict in TypeVar and it works in mypy at least:

    from typing import TypedDict, TypeVar
    
    class Attrs(TypedDict):
        key: str
    
    T = TypeVar("T", bound=Attrs)  # does not complain

    This seems to work in mypy but I'm afraid there is not PEP for it.

  6. sennalen commented on Jan 7, 2025

    @sennalen
    T = TypeVar("T", bound=Attrs)  # does not complain

    The trouble is Unpack[T] does not accept a TypeVar in place of a concrete TypedDict, regardless of being bounded by a TypedDict

  7. mharding-hpe commented on May 3, 2025

    @mharding-hpe

    I would also very much like to see this. I stumbled across this limitation when trying to implement a generic class with a typevar that specifies the kwargs a given method can accept.

  8. t1m013y commented on Jun 29, 2025

    @t1m013y

    I need this feature too.

    I am making a generic class that stores configuration data for my application. Also it takes some metadata as **kwargs in __init__ method. I want to add typing to it using Generic and TypedDict.

    TV = TypeVar("TV")
    
    
    class MyClass(Generic[TV]):
        init_kwargs: TV
    
        def __init__(self, **kwargs: Unpack[TV]) -> None:
            self.init_kwargs = kwargs

    Usage example:

    class MyTD(TypedDict, total=False):
        arg1: int
        arg2: str
    
    
    a: MyClass[MyTD] = MyClass(arg1=4, arg2="foo")
    b: MyClass[MyTD] = MyClass(arg1="bar", arg2=6)  # Should be type error here
    reveal_type(a.init_kwargs['arg1'])  # Should be int
    reveal_type(a.init_kwargs['arg2'])  # Should be str

    But type checker (mypy) throws error:

        def __init__(self, **kwargs: Unpack[TV]) -> None:
    #                                       ^^
    #                                       Unpack item in ** argument must be a TypedDict
  9. RBerga06 commented on Dec 8, 2025

    @RBerga06

    Related: #1395

  10. frezX commented on Jan 10, 2026

    @frezX

    I need it too

    class Example[KW: type[TypedDict]]:
        def __init__(self, **kwargs: Unpack[KW]) -> None:
            ...
    
    
    class ExampleKwargs(TypedDict):
        foo: int
        bar: str
    
    
    example: Example[ExampleKwargs] = Example(
        foo=123,  # <- OK
        bar=456  # <- Expected type 'str', got 'int' instead
    )
  11. faithleysath commented on Jan 11, 2026

    @faithleysath

    I need it too, I need Unpack can take a TypeVar which bond to TypeDict.

  12. andrewsonin commented on Apr 11, 2026

    @andrewsonin

    I need it too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: featureDiscussions about new features for Python's type annotations

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions