|
I'd like to know if there's a way to type a class, where an init arg determines the signature of another method on the class. For example: |
Answered by
henribru
Oct 24, 2023
Replies: 2 comments 3 replies
|
Here's a solution that works with pyright. It doesn't work with mypy because of various bugs and limitations in how it handles from typing import Literal, overload
class X[T]:
@overload
def __new__(cls, grouped: Literal[True]) -> X[list[T]]:
...
@overload
def __new__(cls, grouped: Literal[False]) -> X[T]:
...
def __new__(cls, grouped: bool) -> X[list[T]] | X[T]:
...
def x(self, takes: T) -> None:
pass
x1 = X[int](True)
reveal_type(x1) # X[list[int]]
x2 = X[int](False)
reveal_type(x2) # X[int] |
0 replies
|
For an alternative that works in Mypy, it's doable by introducing another generic parameter: from typing import Literal, overload, TypeVar, Generic
T = TypeVar("T")
Grouped = TypeVar("Grouped", bound=bool)
class X(Generic[T, Grouped]):
def __init__(self, grouped: Grouped) -> None: pass
@overload
def x(self: X[T, Literal[True]], takes: list[T]) -> None:
pass
@overload
def x(self: X[T, Literal[False]], takes: T) -> None:
pass
def x(self, takes: T | list[T]) -> None:
pass
x1 = X[int, Literal[True]](True)
reveal_type(x1.x) # def (takes: builtins.list[builtins.int])
x2 = X[int, Literal[False]](False)
reveal_type(x2.x) # def (takes: builtins.int)
|
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Oh yes, actually it does, but the bound needs to be
Literal[True, False]