Closed mattdeutsch closed 1 hour ago
I recommend reading this documentation to better understand the core concepts for static typing.
You should think of a type annotation as a declaration. The statement s: str | None
declares that any value assigned to variable s
must conform with the type str | None
. It is the job of a static type checker to enforce such declarations. The Python typing spec provides assignability rules that dictate which types are assignable to other types. For example, a value of type Literal["hi"]
is assignable to a variable that is declared to accept values of type str | None
, but a value of type Literal[1]
is not assignable.
When a value is assigned to a variable, a static type checker will track its locally-narrowed type. This type may be narrower (more specific) than the variable's declared type.
def func(x: str | None):
reveal_type(x) # str | None
x = "hi"
reveal_type(x) # Literal["hi"]
x = None
reveal_type(x) # None
x = 1 # Type violation
Here's a minimal recreation:
From what I can gather, Pylance is typing
naked_dict
asdict[Unknown, Unknown]
, and inferring thats
must be of typeUnknown
orNone
because of the signature ofdict.get
. That's clearly WAI.What's surprising to me is that Pylance ignores my type annotation of
str | None
. I would expect that in cases where I have more information than the type system, that I am able to tell it what I know about the system (in this case, I know that the key"key"
innaked_dict
, when present, always points to a string). Why does Pylance fight with me on this and claim thats
is of typeUnknown | None
?I'm quite confident that this is just me misunderstanding the goals of Pylance as a project, so I'm unwilling to file this as a bug. But I would like to understand why this choice has been made, and appreciate the time of any contributors willing to help me understand. Is it a problem with the LSP?
Thanks!