Proposal: Add a "true union" / merge / join / intersection type annotation

This proposal is to add a type annotation to indicate that a true union of multiple types are returned.

Currently, the union of multiple types is interpreted as an “or”

This would be an “and”. A common example people use is a mock object, which would be the true union of mock object’s attributes and the spec it is mocking. Another example where this may be helpful is for class factories that may return a class with mixins added. You could also in theory type check parameters the presence of mixins without coupling the logic to the implementation via protocols.

This is an unusual use case. It’s asking for a way to get type checkers to play nice with things that are the product of a dynamic language. Besides the mixin example the only other use case I can think of is when you implement getattr logic that falls-back to a provided type or object.

A real world example is my megamock library. This is how I get a true union type in the IDE without having mypy complain about the MegaMock specific attributes:

        # hack to get static type inference to think this is a true union
        # of the two classes
        def helper(obj) -> type[MegaMock[T, MegaMock | T] | T]:
            return cast(type[MegaMock | T], lambda: obj)

        return helper(
            MegaMock(
                spec=spec,
...
            ),
        )()

The implementation I gave is very non-ideal. Mypy could fix whatever allows this to work and then the code would no longer function. Likewise, the returned value isn’t type checked, and adding type annotations to the return value of this function breaks this.

I’m not sure what this should be called. I’d imagine the shorthand syntax would be &

See: Introduce an Intersection · Issue #213 · python/typing · GitHub and GitHub - CarliJoy/intersection_examples: Python Typing Intersection examples

3 Likes

Thanks! Glad to see there’s recent work on this.