While this doesn't answer the question as asked, I think you might also reconsider why you're using a TypedDict with a string instead of a proper class to hold the enum (instead of a str, since DisbursementType really does seem like an enum), and which can then employ some custom serialization logic.
For example:
import dataclasses as dc import json from enum import Enum class Transaction(Enum): DISBURSEMENT = "disbursement" REFUND = "refund" ROLLBACK = "rollback" def __str__(self): return self.value @dc.dataclass class Disbursement: transaction: Transaction id_: str amount: float def __str__(self): return json.dumps(dc.asdict(self), default=str) if __name__ == "__main__": disbursement = Disbursement( Transaction.REFUND, "1", 4400.24, ) print(disbursement)
$ mypy example.py Success: no issues found in 1 source file $ python3 example.py {"transaction": "refund", "id_": "1", "amount": 4400.24}
Alternatively, you can have your enum inherit from str and simplify a few things:
import dataclasses as dc import json from enum import Enum class Transaction(str, Enum): DISBURSEMENT = "disbursement" REFUND = "refund" ROLLBACK = "rollback" @dc.dataclass class Disbursement: transaction: Transaction id_: str amount: float def __str__(self): return json.dumps(dc.asdict(self)) if __name__ == "__main__": disbursement = Disbursement( Transaction.REFUND, "1", 4400.24, ) print(disbursement)
Other considerations:
Finally, I wanted to note that defining __str__ on my Enum did not do what I expected it to do using your TypedDict example above; that's because str(mydict) calls repr to provide each of mydict.values:
class Example: def __repr__(self): print("I called repr!") return "from repr" def __str__(self): print("I called str!") return "from str" if __name__ == "__main__": print(f"example: {Example()}\n") d = {"example": Example()} print(f"in a dict: {d}")
$ python3 foo.py I called str! example: from str I called repr! in a dict: {'example': from repr}
Additionally, you can't add custom methods to a TypedDict; if you change Example to inherit from TypedDict and rerun that last example, you'll see that neither __repr__ nor __str__ is called, and unfortunately there is no runtime error either (mypy helpfully warns error: Invalid statement in TypedDict definition; expected "field_name: field_type"). Because serialization logic seems to belong to Disbursement, I changed it to a somewhat similar class that allows me to customize its __str__: a dataclass.
Literalwould be your best bet...