Skip to content
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

"'field' in typed_dict_union" discrimination #13802

Closed
ikonst opened this issue Oct 3, 2022 · 4 comments
Closed

"'field' in typed_dict_union" discrimination #13802

ikonst opened this issue Oct 3, 2022 · 4 comments
Labels
feature topic-type-narrowing Conditional type narrowing / binder topic-typed-dict

Comments

@ikonst
Copy link
Contributor

ikonst commented Oct 3, 2022

Feature

Similar to tagged unions, I wish an in check could discriminate the following:

class A(TypedDict)
   foo: int

class B(TypedDict):
   bar: int

union = Union[A, B]
value: int
if 'foo' in union:
  value = union['foo']
else:
  value = union['bar']

Similarly:

value: int
if foo := union.get('foo'):
  value = foo
else:
  value = union['bar']
@ikonst ikonst added the feature label Oct 3, 2022
@JelleZijlstra JelleZijlstra added topic-typed-dict topic-type-narrowing Conditional type narrowing / binder labels Oct 3, 2022
@erictraut
Copy link

This has been discussed previously in various typing forums. (I can't find the threads currently, but perhaps someone else can find a pointer.)

The problem here is that narrowing based on field discrimination within a TypedDict isn't type safe unless that TypedDict class is marked @final. Otherwise it would be possible for a subclass of B to add a field foo.

With an @final decorator on A and B it should be possible for mypy to implement type narrowing based on field discrimination. I've implemented this support in pyright. Currently, mypy emits an error if you attempt to add a @final decorator to a TypedDict class.

from typing import TypedDict, final

@final
class A(TypedDict):
    foo: int

@final
class B(TypedDict):
    bar: int

def func(union: A | B):
    if "foo" in union:
        reveal_type(union)  # A
    else:
        reveal_type(union)  # B

@hauntsaninja
Copy link
Collaborator

#7981 is probably the right mypy issue to track this

@ikonst
Copy link
Contributor Author

ikonst commented Oct 4, 2022

Thanks for the pointer @hauntsaninja, indeed appears to be addressed in #13557. Happy to test once it makes its way into the next release.

@hauntsaninja
Copy link
Collaborator

Only half the feature is implemented; want to take a shot at completing it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature topic-type-narrowing Conditional type narrowing / binder topic-typed-dict
Projects
None yet
Development

No branches or pull requests

4 participants