[ty] Reuse common TypedDict constraints through intersections (#26747)
## Summary
Prior to this change, the common-protocol-constraint optimization for
unions of `TypedDict`s did not apply after an `isinstance(value, dict)`
check. Narrowing represents each surviving arm as an intersection with
`Top[dict[Unknown, Unknown]]`, so a call like `dict(value)` fell back to
combining equivalent generic protocol constraints independently across
every union member:
```python
from typing import Literal, TypedDict
class A(TypedDict):
tag: Literal["a"]
class B(TypedDict):
tag: Literal["b"]
def copy(value: A | B | str) -> None:
if isinstance(value, dict):
reveal_type(dict(value)) # dict[str, object]
```
With a sufficiently wide union, that fallback exhibited pathological
runtime. On the issue's 21-arm reproduction, the pre-fix build did not
complete within ten seconds; the optimized path completes in under 0.2
seconds.
We now recognize intersections containing a positive `TypedDict` as
`TypedDict` alternatives, while retaining the complete intersection when
comparing its protocol constraints with `Mapping[str, object]`.
Closes https://github.com/astral-sh/ty/issues/3974.
Co-authored-by: Nate Bracy <nate@bracy.dev>