What's the difference between a constrained TypeVar and a Union?
T
's type must be consistent across multiple uses within a given scope, while U
's does not.
With a Union
type used as function parameters, the arguments as well as the return type can all be different:
U = Union[int, str]def union_f(arg1: U, arg2: U) -> U: return arg1x = union_f(1, "b") # No error due to different typesx = union_f(1, 2) # Also no errorx = union_f("a", 2) # Also no errorx # And it can't tell in any of the cases if 'x' is an int or string
Compare that to a similar case with a TypeVar
where the argument types must match:
T = TypeVar("T", int, str)def typevar_f(arg1: T, arg2: T) -> T: return arg1y = typevar_f(1, "b") # "Expected type 'int' (matched generic type 'T'), got 'str' insteady = typevar_f("a", 2) # "Expected type 'str' (matched generic type 'T'), got 'int' insteady = typevar_f("a", "b") # No errory # It knows that 'y' is a stringy = typevar_f(1, 2) # No errory # It knows that 'y' is an int
So, use a TypeVar
if multiple types are allowed, but different usages of T
within a single scope must match each other. Use a Union
if multiple types are allowed, but different usages of U
within a given scope don't need to match each other.