diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index e9d5a61..3013355 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -38,9 +38,9 @@ _ErrorMessagesToOverride = Dict[str, Any] _T = TypeVar("_T", bound="Field") # __set__ value type -_ST = TypeVar("_ST") +_ST = TypeVar("_ST", contravariant=True) # __get__ return type -_GT = TypeVar("_GT") +_GT = TypeVar("_GT", covariant=True) class Field(RegisterLookupMixin, Generic[_ST, _GT]): _pyi_private_set_type: Any diff --git a/tests/typecheck/fields/test_base.yml b/tests/typecheck/fields/test_base.yml index 48ce577..42cd2e5 100644 --- a/tests/typecheck/fields/test_base.yml +++ b/tests/typecheck/fields/test_base.yml @@ -150,4 +150,18 @@ username = models.CharField(max_length=100) class MyModel(AuthMixin, models.Model): - pass \ No newline at end of file + pass +- case: can_narrow_field_type + main: | + from typing import cast, NewType + from django.db import models + Year = NewType("Year", int) + class Book(models.Model): + published = cast(models.Field[Year, Year], models.IntegerField()) + book = Book() + reveal_type(book.published) # N: Revealed type is 'main.Year*' + book.published = 2006 # E: Incompatible types in assignment (expression has type "int", variable has type "Year") + book.published = Year(2006) + reveal_type(book.published) # N: Revealed type is 'main.Year*' + def accepts_int(arg: int) -> None: ... + accepts_int(book.published)