Truthiness check narrows NewType(float) to TFloat & ~AlwaysFalsy, which is rejected as float (original) (raw)
Summary
This looks like a truthiness-narrowing issue involving NewType(float). This behavior is not observed in NewType(str).
Minimal reproduction (playground link):
from typing import NewType, reveal_type
TFloat = NewType("TFloat", float)
def takes_float(x: float) -> None: ...
t = TFloat(1.0)
takes_float(t) # OK
if t:
reveal_type(t) # TFloat & ~AlwaysFalsy
takes_float(t) # error: Expected int | float, found TFloat & ~AlwaysFalsy
Motivating example (Optional case + comparison with float | None):
from typing import NewType, reveal_type
TFloat = NewType("TFloat", float)
def takes_float(x: float) -> None: ...
def optional_tfloat() -> TFloat | None: ... def optional_float() -> float | None: ...
t = optional_tfloat() if t: reveal_type(t) # TFloat & ~AlwaysFalsy takes_float(t) # error
f = optional_float() if f: reveal_type(f) # (int & ~AlwaysFalsy) | (float & ~AlwaysFalsy) takes_float(f) # OK
Version
ty 0.0.20