# \`dataclasses.asdicttype(type)\`

**URL:** <https://discuss.python.org/t/dataclasses-asdicttype-type/103448>\
**Category:** Ideas\
**Tags:** stdlib\
**Created:** [August 31, 2025, 10:10am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448 "2025-08-31T10:10:17Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![maciek](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/maciek/32/596_2.png) [@maciek](https://discuss.python.org/u/maciek)\
**Post date:** [August 31, 2025, 10:10am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/1 "2025-08-31T10:10:17Z")

</div>

From [python/typing](https://matrix.to/#/#python_typing:gitter.im) Gitter:

> martin ➬: I have a couple of dataclasses and matching `TypedDict`s and it pains me _so much_ to have all this redundancy. Why? Why doesn’t there seem to be a way to create a `TypedDict` from a dataclass, like I can make a `TypeAdapter` from a Pydantic model?
> 
> or at least let me use a `TypedDict` as the basis for the dataclasses. But no, right now it seems I have to define two classes with identical fields and god forbid I make a mistake and one has `a:int` and the other `a:str`, which is a function of redundancy and never a question of “if” but only ever “when”.

I agree with the general sentiment, and already stumbled upon such redundancy in my work.

Would `dataclasses.asdicttype(type)` be accepted in [`dataclasses`](https://docs.python.org/pl/3/library/dataclasses.html) stdlib module?

Alternatively it could be `dataclasses.astypeddict(type)`, but that could be confusing by similarity to `dataclasses.asdict(obj)`.

Similar functionality is currently provided as [ubertyped](https://github.com/ViliamV/ubertyped) (MIT-licensed).

---

<div class="post-metadata">

**Author:** ![dr\_carlos](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dr_carlos/32/30461_2.png) [@dr\_carlos](https://discuss.python.org/u/dr_carlos)\
**Post date:** [August 31, 2025, 10:25am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/2 "2025-08-31T10:25:03Z")

</div>

Might you be able to briefly describe the use-case?

I probably just don’t use `dataclasses` or `TypedDict`s enough, but after reading the README for the ubertyped project you linked, which certainly describes the features very well, I don’t understand what the reason to use that library/this function would be.

Are dataclasses missing some first-class support in typing that `TypedDict`s have?

---

<div class="post-metadata">

**Author:** ![maciek](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/maciek/32/596_2.png) [@maciek](https://discuss.python.org/u/maciek)\
**Post date:** [August 31, 2025, 10:34am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/3 "2025-08-31T10:34:02Z")

</div>

Data serialisation is the main use case. We can have adapters that convert types to accept external data or to output a JSON through a dict between some codebase layers. It can also be used while refactoring, to let gradually switch from a dict structure to a dataclass.

Then `asdicttype` would serve as a convenience function, to avoid redundancy.

---

<div class="post-metadata">

**Author:** ![maciek](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/maciek/32/596_2.png) [@maciek](https://discuss.python.org/u/maciek)\
**Post date:** [August 31, 2025, 11:03am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/4 "2025-08-31T11:03:34Z")

</div>

While support for `dataclasses.asdict(obj)` returning `TypedDict` [is blocked](https://github.com/python/mypy/issues/10104#issuecomment-1693611743), it could serve as a way to enable semi-manually specifying the type:

```python
from dataclasses import asdict, asdicttype, dataclass
from typing import cast

@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0 

i = InventoryItem(name='a', unit_price=1.0)

id1 = asdict(i)
# reveal_type(id1) # Revealed type is "builtins.dict[builtins.str, Any]"

id2 = cast(asdicttype(InventoryItem), id1)
# reveal_type(id2) # Revealed type is [anonymous typed dict derived from InventoryItem]

```

---

<div class="post-metadata">

**Author:** ![Tinche](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tinche/32/12507_2.png) [@Tinche](https://discuss.python.org/u/Tinche)\
**Post date:** [August 31, 2025, 11:43am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/5 "2025-08-31T11:43:27Z")

</div>

Can you speak more to the use cases? I still don’t understand what the point is of this intermediate typeddict.

---

<div class="post-metadata">

**Author:** ![dr\_carlos](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dr_carlos/32/30461_2.png) [@dr\_carlos](https://discuss.python.org/u/dr_carlos)\
**Post date:** [August 31, 2025, 12:05pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/6 "2025-08-31T12:05:46Z")

</div>

If I understand correctly, a minimal example (based on yours) would be:

```python
from dataclasses import asdict, asdicttype, dataclass

@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0 

i = InventoryItem(name='a', unit_price=1.0)

# Then later on you want to serialise it
to_serialise: asdicttype(i) = asdict(i) 

```

And this would work without needing a cast?

---

<div class="post-metadata">

**Author:** ![maciek](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/maciek/32/596_2.png) [@maciek](https://discuss.python.org/u/maciek)\
**Post date:** [August 31, 2025, 12:48pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/7 "2025-08-31T12:48:02Z")

</div>

> And this would work without needing a cast?

Actually it occurs that [`dict` is not compatible with `TypedDict`](https://github.com/python/mypy/issues/10104#issuecomment-1693611743) which is more general type (covers also `defaultdict` and also some other mappings classes). So it would still require a cast now (or at least until [mypy#10104](https://github.com/python/mypy/issues/10104) is implemented/merged). The minimal example would be:

```python
from dataclasses import asdict, asdicttype, dataclass
from typing import cast

@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0 

i = InventoryItem(name='a', unit_price=1.0)

to_serialize = cast(asdicttype(InventoryItem), i)
# reveal_type(to_serialize) # Revealed type is [anonymous typed dict derived from InventoryItem]

```

---

<div class="post-metadata">

**Author:** ![Monarch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/monarch/32/18530_2.png) [@Monarch](https://discuss.python.org/u/Monarch)\
**Post date:** [August 31, 2025, 8:58pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/8 "2025-08-31T20:58:32Z")

</div>

Converting dataclass-like objects to dictionary is a very common pattern:

- [`dataclasses.asdict(...) -> dict[str, Any]`](https://github.com/python/typeshed/blob/016703a5c9e735ec49a68e948cd4515a5da5898a/stdlib/dataclasses.pyi#L67)
- [`pydantic.BaseModel.model_dump(...) -> dict[str, Any]`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_dump)
- [`msgspec.to_builtins(...) -> Any`](https://github.com/jcrist/msgspec/blob/bc60e96772c5e8a3babff967d86a9e7dfcdbfb1b/msgspec/ __init__.pyi#L149)
- [`cattrs.unstructure(...) -> Any`](https://catt.rs/en/stable/cattrs.html#cattrs.BaseConverter.unstructure)\[1\]

As you can notice, all of these essentially lose all the types with `dict[str, Any]` despite the fact that the resulting dictionary has the same keys as the fields on the original dataclass-like object.

I could imagine a typing construct like:

```py
def asdict[T: DataClassLike](obj: T) -> AsTypedDict[T]: ...

```

To allow typing the above pattern.

The devil, however, is in the details so:

- Should `AsTypedDict[T]` be recursive and represent nested dataclass-like objects as nested typed dicts? (Probably yes given that’s what common runtime behaviour seems to be)
- How should `AsTypedDict[T]` handle fields that are typed as `field: T | None` – `Required[T | None]` or `NotRequired[T]`?
- Probably more edge cases I can’t think of.

* * *

1. `cattrs` has customizable unstructure strategies, so it can probably never be typed accurately. However, the default strategy is similar to `asdict`.

---

<div class="post-metadata">

**Author:** ![Tinche](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tinche/32/12507_2.png) [@Tinche](https://discuss.python.org/u/Tinche)\
**Post date:** [August 31, 2025, 9:22pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/9 "2025-08-31T21:22:38Z")

</div>

> [@Monarch](#):
>
> fact that the resulting dictionary has the same keys as the fields on the original dataclass-like object

It’s not that simple. In cattrs at least, the result may only have a subset of the attribute names, the keys may be renamed (either to their alias or an arbitrary string), and the result may not actually be a dict at all (it may be a tuple, if that’s the configuration applied, or anything else really).

I still don’t really understand what is it that folks want to actually do with this resulting dictionary that requires exact typing? Usually it’s immediately passed over to a serialization library, which doesn’t really care about the type (it’s very dynamic).

---

<div class="post-metadata">

**Author:** ![madduck](https://avatars.discourse-cdn.com/v4/letter/m/f9ae1b/32.png) [@madduck](https://discuss.python.org/u/madduck)\
**Post date:** [September 3, 2025, 6:33pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/10 "2025-09-03T18:33:23Z")

</div>

Thank you @maciek for forwarding my message from Gitter/Matrix!

I welcome the opportunity to respond to @Tinche’s request for context, which I’ll shamelessly duplicate from [this discussion over in the Pydantic forum](https://github.com/pydantic/pydantic/discussions/12204). The following talks a about Pydantic `BaseModel`, but the exact same idea applies to `dataclasses`.

One feature of FastAPI I’m enamoured with is the idea of [query parameter models](https://fastapi.tiangolo.com/tutorial/query-param-models/), and it works like this: Say you have a model with `a:str` and `b:int`, then you can tell FastAPI that an API endpoint takes e.g. GET query parameters `a:str` and `b:int` simply by telling FastAPI that the model describes valid query string parameters. The same works for cookies and headers (I cannot link to the docs for these, as I am new user here who may only include two links per post… :().

This got me thinking: say I have two models (or `dataclasses`) describing parameters:

```Python
class One(BaseModel):
    a: str

class Two(BaseModel):
    b: int

```

FastAPI can form a union of those two and my API endpoint suddently knows how to handle `a` and `b`.

Now, assume I want to define a function that takes `a` and `b` as parameters, is there a way to reuse those `BaseModel` derivatives for typing a `**kwargs` dictionary, similar to if the above two were `TypedDict` definitions? Basically something like `Unpack` that works with Pydantic’s `BaseModel`? Like so:

```Python
def some_function(**kwargs: Unpack[One | Two]) -> None:
    ...

```

and that would mean that type checkers would type-check `kwargs` in the function call and warn if anything other than `a:str` and `b:int` was passed?

Looking forward to any insights or ideas how to achieve the above. Thank you!

---

<div class="post-metadata">

**Author:** ![Viicos](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/viicos/32/14616_2.png) [@Viicos](https://discuss.python.org/u/Viicos)\
**Post date:** [September 4, 2025, 6:45am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/11 "2025-09-04T06:45:13Z")

</div>

@madduck I think this boils down to first having a way to convert a dataclass-like type to a TypedDict, that can then be used in `Unpack[]`. I’m not sure the union is the right way to express this. You’d probably need to first create a subclass of `One` and `Two` or have a way to create intersection types (in [the TypeScript sense](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#intersection-types)).

I’m currently in the process of trying to spec out a way to create TypedDicts dynamically using a comprehension syntax ([Inlined typed dicts and typed dict comprehensions - #12 by Viicos](https://discuss.python.org/t/inlined-typed-dicts-and-typed-dict-comprehensions/68921/12)). While it is hard to keep the scope limited, such TypedDict comprehensions could be created from a dataclass to express the requested feature here.

---

<div class="post-metadata">

**Author:** ![el1s7](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/el1s7/32/28006_2.png) [@el1s7](https://discuss.python.org/u/el1s7)\
**Post date:** [September 5, 2025, 5:20pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/12 "2025-09-05T17:20:48Z")

</div>

> [@Tinche](#):
>
> Can you speak more to the use cases? I still don’t understand what the point is of this intermediate typeddict.

It’s clear there are some use cases for this, otherwise there wouldn’t be multiple people requesting this feature (e.g. related requests [[1]](https://github.com/python/typing/issues/1495), [[2]](https://discuss.python.org/t/typing-unpack-for-kwargs-with-self-or-dataclass-classes/43001)).

Using dataclasses as \*\*`kwargs` arguments is the most common one.

---

<div class="post-metadata">

**Author:** ![Tinche](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tinche/32/12507_2.png) [@Tinche](https://discuss.python.org/u/Tinche)\
**Post date:** [September 5, 2025, 6:16pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/13 "2025-09-05T18:16:48Z")

</div>

Neither of the issues you mention are about serialization (although serialization gets mentioned early on in the first one), but about wrapping a (data)class’s ` __init__ ` in a type-safe way.

That’s an interesting use case but could probably be solved more elegantly and generally than converting a dataclass type into a typed dict to be used with Unpack. Those use cases also need the typeddict conversion to be shallow, whereas the serialization use case would probably need it to be deep (but I still don’t understand the serialization use case fully).

For example, it’d be cool if we could annotate kwargs (maybe \*args too) as having the same type as a different callable’s kwargs, or the return value as having the same type as a different callable’s return value. It would probably solve these issues and help with other cases of function composition, too.

---

<div class="post-metadata">

**Author:** ![Monarch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/monarch/32/18530_2.png) [@Monarch](https://discuss.python.org/u/Monarch)\
**Post date:** [September 5, 2025, 8:38pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/14 "2025-09-05T20:38:03Z")

</div>

> [@Tinche](#):
>
> I still don’t really understand what is it that folks want to actually do with this resulting dictionary that requires exact typing? Usually it’s immediately passed over to a serialization library, which doesn’t really care about the type (it’s very dynamic).

Personally, I’ve run into two main cases where this is useful:

1. Building an immutable object from a dictionary

2. Type hinting `from_dict` and `to_dict` methods on my dataclass-like objects

---

<div class="post-metadata">

**Author:** ![Tinche](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tinche/32/12507_2.png) [@Tinche](https://discuss.python.org/u/Tinche)\
**Post date:** [September 5, 2025, 9:32pm UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/15 "2025-09-05T21:32:50Z")

</div>

> [@Monarch](#):
>
> Type hinting `from_dict` and `to_dict` methods on my dataclass-like objects

Got it. My followup question is: what do you then do with the result of `to_dict()` that you can’t do with just an instance of `Foo`?

---

<div class="post-metadata">

**Author:** ![maciek](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/maciek/32/596_2.png) [@maciek](https://discuss.python.org/u/maciek)\
**Post date:** [September 26, 2025, 10:51am UTC](https://discuss.python.org/t/dataclasses-asdicttype-type/103448/16 "2025-09-26T10:51:58Z")

</div>

To sum up from my side, I hope that [support for asdict returning TypedDict](https://github.com/python/mypy/issues/10104) would be enabled by the [intersection type](https://github.com/python/typing/issues/213) and merged into mypy in the future. That would be a great improvement.

I think after above is working, we can get back to this thread (at least me personally 🙂 ).
