diff --git a/icontract/_checkers.py b/icontract/_checkers.py
index 3e7e6d6..30ab186 100644
--- a/icontract/_checkers.py
+++ b/icontract/_checkers.py
@@ -4,6 +4,7 @@ import inspect
 from typing import Callable, Any, Iterable, Optional, Tuple, List, Mapping, MutableMapping, Dict
 
 import icontract._represent
+from icontract._globals import CallableT
 from icontract._types import Contract, Snapshot
 from icontract.errors import ViolationError
 
@@ -13,7 +14,7 @@ from icontract.errors import ViolationError
 # pylint: disable=unsubscriptable-object
 
 
-def _walk_decorator_stack(func: Callable[..., Any]) -> Iterable['Callable[..., Any]']:
+def _walk_decorator_stack(func: CallableT) -> Iterable['CallableT']:
     """
     Iterate through the stack of decorated functions until the original function.
 
@@ -27,9 +28,9 @@ def _walk_decorator_stack(func: Callable[..., Any]) -> Iterable['Callable[..., A
     yield func
 
 
-def find_checker(func: Callable[..., Any]) -> Optional[Callable[..., Any]]:
+def find_checker(func: CallableT) -> Optional[CallableT]:
     """Iterate through the decorator stack till we find the contract checker."""
-    contract_checker = None  # type: Optional[Callable[..., Any]]
+    contract_checker = None  # type: Optional[CallableT]
     for a_wrapper in _walk_decorator_stack(func):
         if hasattr(a_wrapper, "__preconditions__") or hasattr(a_wrapper, "__postconditions__"):
             contract_checker = a_wrapper
@@ -228,7 +229,7 @@ class _Old:
     def __init__(self, mapping: Mapping[str, Any]) -> None:
         self.__dict__.update(mapping)
 
-    def __getattr__(self, item):
+    def __getattr__(self, item: str) -> Any:
         raise AttributeError("The snapshot with the name {!r} is not available in the OLD of a postcondition. "
                              "Have you decorated the function with a corresponding snapshot decorator?".format(item))
 
@@ -236,7 +237,7 @@ class _Old:
         return "a bunch of OLD values"
 
 
-def decorate_with_checker(func: Callable[..., Any]) -> Callable[..., Any]:
+def decorate_with_checker(func: CallableT) -> CallableT:
     """Decorate the function with a checker that verifies the preconditions and postconditions."""
     assert not hasattr(func, "__preconditions__"), \
         "Expected func to have no list of preconditions (there should be only a single contract checker per function)."
@@ -311,7 +312,7 @@ def decorate_with_checker(func: Callable[..., Any]) -> Callable[..., Any]:
             for contract in postconditions:
                 _assert_postcondition(contract=contract, resolved_kwargs=resolved_kwargs)
 
-        return result
+        return result  # type: ignore
 
     # Copy __doc__ and other properties so that doctests can run
     functools.update_wrapper(wrapper=wrapper, wrapped=func)
@@ -330,7 +331,7 @@ def decorate_with_checker(func: Callable[..., Any]) -> Callable[..., Any]:
     setattr(wrapper, "__postcondition_snapshots__", [])
     setattr(wrapper, "__postconditions__", [])
 
-    return wrapper
+    return wrapper  # type: ignore
 
 
 def _find_self(param_names: List[str], args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Any:
@@ -344,7 +345,7 @@ def _find_self(param_names: List[str], args: Tuple[Any, ...], kwargs: Dict[str,
     return instance
 
 
-def _decorate_with_invariants(func: Callable[..., Any], is_init: bool) -> Callable[..., Any]:
+def _decorate_with_invariants(func: CallableT, is_init: bool) -> CallableT:
     """
     Decorate the function ``func`` of the class ``cls`` with invariant checks.
 
@@ -391,7 +392,7 @@ def _decorate_with_invariants(func: Callable[..., Any], is_init: bool) -> Callab
 
     setattr(wrapper, "__is_invariant_check__", True)
 
-    return wrapper
+    return wrapper  # type: ignore
 
 
 class _DummyClass:
@@ -403,7 +404,7 @@ class _DummyClass:
 _SLOT_WRAPPER_TYPE = type(_DummyClass.__init__)  # pylint: disable=invalid-name
 
 
-def _already_decorated_with_invariants(func: Callable[..., Any]) -> bool:
+def _already_decorated_with_invariants(func: CallableT) -> bool:
     """Check if the function has been already decorated with an invariant check by going through its decorator stack."""
     already_decorated = False
     for a_decorator in _walk_decorator_stack(func=func):
@@ -467,9 +468,9 @@ def add_invariant_checks(cls: type) -> None:
         setattr(cls, name, wrapper)
 
     for name, prop in names_properties:
-        fget = _decorate_with_invariants(func=prop.fget, is_init=False) if prop.fget else None
-        fset = _decorate_with_invariants(func=prop.fset, is_init=False) if prop.fset else None
-        fdel = _decorate_with_invariants(func=prop.fdel, is_init=False) if prop.fdel else None
-
-        new_prop = property(fget=fget, fset=fset, fdel=fdel, doc=prop.__doc__)
+        new_prop = property(  # type: ignore
+            fget=_decorate_with_invariants(func=prop.fget, is_init=False) if prop.fget else None,
+            fset=_decorate_with_invariants(func=prop.fset, is_init=False) if prop.fset else None,
+            fdel=_decorate_with_invariants(func=prop.fdel, is_init=False) if prop.fdel else None,
+            doc=prop.__doc__)
         setattr(cls, name, new_prop)
diff --git a/icontract/_decorators.py b/icontract/_decorators.py
index aaf62bb..65d3a08 100644
--- a/icontract/_decorators.py
+++ b/icontract/_decorators.py
@@ -2,6 +2,7 @@
 import reprlib
 from typing import Callable, Optional, Union, Any, List  # pylint: disable=unused-import
 
+from icontract._globals import CallableT
 from icontract._types import Contract, Snapshot
 
 import icontract._checkers
@@ -18,11 +19,11 @@ class require:  # pylint: disable=invalid-name
 
     # pylint: disable=too-many-instance-attributes
     def __init__(self,
-                 condition: Callable[..., bool],
+                 condition: Callable[..., Any],
                  description: Optional[str] = None,
                  a_repr: reprlib.Repr = icontract._globals.aRepr,
                  enabled: bool = __debug__,
-                 error: Union[Callable[..., Exception], type] = None) -> None:
+                 error: Optional[Union[Callable[..., Exception], type]] = None) -> None:
         """
         Initialize.
 
@@ -54,7 +55,7 @@ class require:  # pylint: disable=invalid-name
 
         self._contract = Contract(condition=condition, description=description, a_repr=a_repr, error=error)
 
-    def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
+    def __call__(self, func: CallableT) -> CallableT:
         """
         Add the precondition to the list of preconditions of the function ``func``.
 
@@ -131,7 +132,7 @@ class snapshot:  # pylint: disable=invalid-name
         if enabled:
             self._snapshot = Snapshot(capture=capture, name=name)
 
-    def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
+    def __call__(self, func: CallableT) -> CallableT:
         """
         Add the snapshot to the list of snapshots of the function ``func``.
 
@@ -179,11 +180,11 @@ class ensure:  # pylint: disable=invalid-name
 
     # pylint: disable=too-many-instance-attributes
     def __init__(self,
-                 condition: Callable[..., bool],
+                 condition: Callable[..., Any],
                  description: Optional[str] = None,
                  a_repr: reprlib.Repr = icontract._globals.aRepr,
                  enabled: bool = __debug__,
-                 error: Union[Callable[..., Exception], type] = None) -> None:
+                 error: Optional[Union[Callable[..., Exception], type]] = None) -> None:
         """
         Initialize.
 
@@ -215,7 +216,7 @@ class ensure:  # pylint: disable=invalid-name
 
         self._contract = Contract(condition=condition, description=description, a_repr=a_repr, error=error)
 
-    def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
+    def __call__(self, func: CallableT) -> CallableT:
         """
         Add the postcondition to the list of postconditions of the function ``func``.
 
@@ -261,11 +262,11 @@ class invariant:  # pylint: disable=invalid-name
     """
 
     def __init__(self,
-                 condition: Callable[..., bool],
+                 condition: Callable[..., Any],
                  description: Optional[str] = None,
                  a_repr: reprlib.Repr = icontract._globals.aRepr,
                  enabled: bool = __debug__,
-                 error: Union[Callable[..., Exception], type] = None) -> None:
+                 error: Optional[Union[Callable[..., Exception], type]] = None) -> None:
         """
         Initialize a class decorator to establish the invariant on all the public methods.
 
diff --git a/icontract/_globals.py b/icontract/_globals.py
index e744d87..2ac0002 100644
--- a/icontract/_globals.py
+++ b/icontract/_globals.py
@@ -2,11 +2,13 @@
 
 import os
 import reprlib
+from typing import TypeVar, Callable
 
 # Default representation instance.
 #
 # The limits are set way higher than reprlib.aRepr since the default reprlib limits are not suitable for
 # the production systems.
+
 aRepr = reprlib.Repr()  # pylint: disable=invalid-name
 aRepr.maxdict = 50
 aRepr.maxlist = 50
@@ -25,3 +27,4 @@ aRepr.maxother = 256
 #
 # Contracts marked with SLOW are also disabled if the interpreter is run in optimized mode (``-O`` or ``-OO``).
 SLOW = __debug__ and os.environ.get("ICONTRACT_SLOW", "") != ""
+CallableT = TypeVar('CallableT', bound='Callable')
diff --git a/icontract/_types.py b/icontract/_types.py
index 13e7d63..b3eb87b 100644
--- a/icontract/_types.py
+++ b/icontract/_types.py
@@ -17,7 +17,7 @@ class Contract:
                  condition: Callable[..., bool],
                  description: Optional[str] = None,
                  a_repr: reprlib.Repr = icontract._globals.aRepr,
-                 error: Union[Callable[..., Exception], type] = None) -> None:
+                 error: Optional[Union[Callable[..., Exception], type]] = None) -> None:
         """
         Initialize.
 

require decorator removes type annotations for mypy
```
$ cat ic.py  
from icontract import require

@require(lambda x: x > 0)
def f1(x: int): return x

def f2(x: int): return 0

f1("this is wrong")
f2("this is too")

$ mypy ic.py              
ic.py:9: error: Argument 1 to "f2" has incompatible type "str"; expected "int"
```

Both function calls are invalid types but mypy only sees the call as f2 as wrong.  The decorator loses the type annotations?

Related https://github.com/python/mypy/issues/3157 


diff --git a/tests/test_mypy_decorators.py b/tests/test_mypy_decorators.py
new file mode 100644
index 0000000..ab3019c
--- /dev/null
+++ b/tests/test_mypy_decorators.py
@@ -0,0 +1,50 @@
+# pylint: disable=missing-docstring
+
+import subprocess
+import tempfile
+import textwrap
+import unittest
+
+
+class TestMypyDecorators(unittest.TestCase):
+    def test_mypy_me(self):
+        with tempfile.NamedTemporaryFile(prefix="mypy_fail_case_", suffix=".py") as tmp:
+            tmp.file.write(
+                textwrap.dedent('''\
+                """Implement a fail case for mypy to test that the types are preserved with the decorators."""
+
+                import icontract
+
+                @icontract.require(lambda x: x > 0)
+                def f1(x: int) -> int:
+                    return x
+                f1("this is wrong")
+
+                @icontract.ensure(lambda result: result > 0)
+                def f2(x: int) -> int:
+                    return x
+                f2("this is wrong")
+
+                @icontract.snapshot(lambda x: x)
+                def f3(x: int) -> int:
+                    return x
+                f3("this is wrong")
+                ''').encode())
+
+            tmp.file.flush()
+
+            proc = subprocess.Popen(['mypy', '--strict', tmp.name], universal_newlines=True, stdout=subprocess.PIPE)
+            out, err = proc.communicate()
+
+            self.assertIsNone(err)
+            self.assertEqual(
+                textwrap.dedent('''\
+                    {path}:8: error: Argument 1 to "f1" has incompatible type "str"; expected "int"
+                    {path}:13: error: Argument 1 to "f2" has incompatible type "str"; expected "int"
+                    {path}:18: error: Argument 1 to "f3" has incompatible type "str"; expected "int"
+                    '''.format(path=tmp.name)),
+                out)
+
+
+if __name__ == '__main__':
+    unittest.main()

pip3 install -e .[dev]
parse_log_pytest
requirements.txt
pytest
3.6
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
astroid==2.3.0
asttokens==1.1.15
attrs==22.2.0
certifi==2021.5.30
coverage==4.5.4
distlib==0.3.9
docutils==0.18.1
filelock==3.4.1
-e git+https://github.com/Parquery/icontract.git@5fec74799dfbd7813d86a90a2dba79ba78a312cf#egg=icontract
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
isort==5.10.1
lazy-object-proxy==1.7.1
mccabe==0.7.0
mypy==0.641
mypy-extensions==0.4.4
packaging==21.3
platformdirs==2.4.0
pluggy==1.0.0
py==1.11.0
pydocstyle==2.1.1
Pygments==2.14.0
pylint==2.1.1
pyparsing==3.1.4
pytest==7.0.1
six==1.17.0
snowballstemmer==2.2.0
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typed-ast==1.1.2
typing_extensions==4.1.1
virtualenv==20.17.1
wrapt==1.16.0
yapf==0.20.2
zipp==3.6.0

name: icontract
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - astroid==2.3.0
      - asttokens==1.1.15
      - attrs==22.2.0
      - coverage==4.5.4
      - distlib==0.3.9
      - docutils==0.18.1
      - filelock==3.4.1
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - isort==5.10.1
      - lazy-object-proxy==1.7.1
      - mccabe==0.7.0
      - mypy==0.641
      - mypy-extensions==0.4.4
      - packaging==21.3
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - py==1.11.0
      - pydocstyle==2.1.1
      - pygments==2.14.0
      - pylint==2.1.1
      - pyparsing==3.1.4
      - pytest==7.0.1
      - six==1.17.0
      - snowballstemmer==2.2.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typed-ast==1.1.2
      - typing-extensions==4.1.1
      - virtualenv==20.17.1
      - wrapt==1.16.0
      - yapf==0.20.2
      - zipp==3.6.0
prefix: /opt/conda/envs/icontract

tests/test_mypy_decorators.py::TestMypyDecorators::test_mypy_me
icontract/_decorators.py icontract/_checkers.py icontract/_types.py icontract/_globals.py
icontract/_decorators.py icontract/_checkers.py icontract/_types.py icontract/_globals.py