microsoft / pyright

Static Type Checker for Python
Other
13.13k stars 1.4k forks source link

`TypeAliasType` is mistakenly considered assignable to the type it represents #8444

Closed InSyncWithFoo closed 2 months ago

InSyncWithFoo commented 2 months ago

Minimal reproducible example (playgrounds: Pyright, Mypy):

type A[T] = T

def f(v: A[str]) -> None:
    ...

f(A[str])  # pyright => no error
           # mypy => error: Argument 1 to "f" has incompatible type "TypeAliasType"; expected "str"
erictraut commented 2 months ago

I think pyright is doing the right thing here. The type of A when used in a value expression is TypeAliasType. The typeshed definition of this class defines a __getitem__ method which returns Any. That means A[0] evaluates to Any, and that explains why you're not seeing an error in this case.

It would be theoretically possible to override the behavior indicated in the typeshed stub, but I generally avoid this. The few times that I've done this have resulted in downstream problems including unexpected side effects and maintainability issues.

For example, the following code is arguably legitimate and should not generate a type violation.

type A[T] = T
x: GenericAlias = A[str]
erictraut commented 2 months ago

@JelleZijlstra, do you have any thoughts on this?

JelleZijlstra commented 2 months ago

At runtime, TypeAliasType.__getitem__ always returns a GenericAlias, so I submitted a typeshed PR (linked above) to reflect that behavior in the stub. With that change, the OP's code should yield a pyright error.