New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow use of Required
and NotRequired
to make an existing typed dict total or optional
#1454
Comments
@CaselIT, you might be interested in this discussion about an approach that would enable what you're proposing but in a more general way, similar to how TypeScript works. |
Sure, that would achieve the same level of features, but just skimming that proposal it seems several years worth of peps. I think the two could be compatible with each other, so if that other proposal is ever accepted these features could be re-defined using that syntax. The main advantage of this limited change is that only type checkers would need to be changes, since the code above is already legal python, not needing additional types or features (if keeping Note that this issue comes from trying to use a typed dict with several keys (about 15) with a mix of required and not-required ones for an api. Trying to define default types for the optional key, add utilities to merge a typed dict with a partial one etc is currently an exercise in frustration if one has ever even tangentially used typescript (or not, it really isn't user friendly). I've ended up defining the same typed dict multiple times to have the various combination of required / not required |
I agree that the more general solution would require a more involved PEP, but your proposed solution would require a PEP too. Your proposed solution would create an ambiguity in the type system because class A(TypedDict):
a: str
class B(TypedDict):
# Does this mean `b` is a not-required field in B?
# Or does it mean that `b` is required but the fields in `A` are not required?
b: NotRequired[A] Ambiguities like this will create problems in the type system. Even if the PEP clearly disambiguates the meaning in this particular usage, there will be others cases — either now or as new features are added — where this ambiguity will cause problems. For this reason, I think it's unlikely for this proposal to gain acceptance, at least in the form you've suggested. |
sure, I'm not saying otherwise, just that the scope is vastly different. Regarding ambiguity, you are indeed right. Note that I've used the For |
This would be useful with "dict factories": class A(TypedDict):
property1: str
property2: str Some default vales for it: default_A: A = {"property1": "a", "property2": "b"} And a naive implementation of factory: def A_factory(**kwargs: Unpack[A]):
ret = default_A.copy()
ret.update(kwargs)
return ret The issues is that all of the properties are required by a type-checker, so actually no default values. Currently it is required to define a new class with all of the properties the same, but optional: class B(TypedDict, total=False):
property1: str
property2: str
def A_factory(**kwargs: Unpack[B]):
... With class B(A, total=False):
pass
class B(A, TypedDict, total=False):
pass But both of them didn't work, as >>> class A(TypedDict):
... a: str
...
>>> class B(A, total=False):
... b: str
...
>>> A.__required_keys__
frozenset({'a'})
>>> B.__required_keys__
frozenset({'a'})
>>> A.__annotations__
{'a': <class 'str'>}
>>> B.__annotations__
{'a': <class 'str'>, 'b': <class 'str'>} This behavior is of course reasonable and in other cases useful, the ability to mark upper class properties as optional/required in subclass would be also useful. The first example in which I just create a duplicate class works, but it gets messy quickly (keeping the second class up-to-date) and when using inheritance in the first class ( def A_factory(**kwargs: Unpack[NotRequired[B]]):
... But as already pointed out, |
@gresm that's basically my use case |
So it's not so uncommon. That's good to know. |
I think the ability of indicating that a typed dict requires all keys or that all are optional would be very useful.
For example to allow defining default values for a particular dict or to return a dict that has been completely assigned from a function
A simple example
This idea is inspired by the analogous types in typescript
Required
andPartial
that are in general very convenient.I think it makes sense having the same behaviour of the typescript counterparts:
NotRequired[X]
is a no op, since X is defined astotal=False
. Same forRequired[A]
.Required/NotRequired
would include all keys of the typed dict and all its superclasses. This differs from howtotal
works. Example:Required/NotRequired
used inline in the TypedDict are not taken into consideration, so the end result is the same independently of how the typed dict is definedThe text was updated successfully, but these errors were encountered: