I want to explain to Pyright that my variables in class and instance have different types. I managed to overload __get__ method to achieve this, but now Pyright complains about initialization of instances. My files: module.py import dataclasses import typing as ty class CmpOperator: sign: str def __init__(self, field_name: str, value: ty.Any): self.field_name = field_name self.value = value class GtCmpOperator(CmpOperator): sign = ">" class Field[T]: def __init__( self, model_name: str, name: str, default_value: T, python_type: ty.Type[T], ): self.default_value = default_value self.model_name = model_name self.name = name self.python_type = python_type def __gt__(self, other: T) -> GtCmpOperator: return GtCmpOperator(f"{self.model_name}.{self.name}", other) def init_model(model: ty.Type[ty.Any]) -> None: if not dataclasses.is_dataclass(model): raise TypeError(f"Model `{model.__name__}` is not a dataclass") for field_name, field_type in ty.get_type_hints(model).items(): field = Field( model.__name__, field_name, getattr(model, field_name, None), field_type, ) setattr(model, field_name, field) def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T: assert isinstance(cmp, CmpOperator) module.pyi import typing as ty class CmpOperator: sign: str def __init__(self, field_name: str, value: ty.Any): self.field_name: str self.value: ty.Any class GtCmpOperator(CmpOperator): ... class Field[T]: def __init__( self, model_name: str, name: str, default_value: T, python_type: ty.Type[T], ): self.default_value: T self.model_name: str self.name: str self.python_type: ty.Type[T] @ty.overload def __get__(self, obj: None, owner: type) -> ty.Self: ... @ty.overload def __get__(self, obj: object, owner: type) -> T: ... @ty.overload def __set__(self, obj: None, value: Field) -> None: ... @ty.overload def __set__(self, obj: object, value: T) -> None: ... def __gt__(self, other: T) -> GtCmpOperator: ... def init_model(model: ty.Type[ty.Any]) -> None: ... def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T: ... main.py import typing as ty from dataclasses import dataclass from module import Field, init_model, some_work @dataclass class Model1: field: int = 0 @dataclass class Model2: # Literal[0] is not assignable to Field[int] field: Field[int] = 0 if __name__ == "__main__": init_model(Model1) assert isinstance(Model1.field, Field) assert isinstance(Model1().field, int) # "bool" is not assignable to "CmpOperator" obj = some_work(Model1, Model1.field > 0) # It`s fine obj = Model1(field=1) init_model(Model2) assert isinstance(Model2.field, Field) assert isinstance(Model2().field, int) # It`s fine obj = some_work(Model2, Model2.field > 0) # Literal[1] is not assignable to Field[int] obj = Model2(field=1) Asserts are true, but Pyright complains about something in both cases. Continue reading...