Repository: litestar-org/litestar

Issue:
Typing: ExceptionHandler Exception type invariant
```py
class ExceptionSubclass(Exception):
    ...

def fn(req: Request, exc: ExceptionSubclass) -> Response:
    ...

e: ExceptionHandler = fn
```

Mypy error:

```
error: Incompatible types in assignment (expression has type "Callable[[Request[Any, Any], ExceptionSubclass], starlite.response.Response[Any]]", variable has type "Callable[[Request[Any, Any], Exception], Union[starlite.response.Response[Any], starlette.responses.Response]]")  [assignment]
```


Discussion:

Resolving patch:
diff --git a/starlite/router.py b/starlite/router.py
--- a/starlite/router.py
+++ b/starlite/router.py
@@ -1,5 +1,5 @@
 import collections
-from typing import TYPE_CHECKING, Dict, ItemsView, List, Optional, Type, Union, cast
+from typing import TYPE_CHECKING, Dict, ItemsView, List, Optional, Union, cast
 
 from pydantic import validate_arguments
 from pydantic_openapi_schema.v3_1_0 import SecurityRequirement
@@ -19,7 +19,7 @@
     AfterResponseHookHandler,
     BeforeRequestHookHandler,
     ControllerRouterHandler,
-    ExceptionHandler,
+    ExceptionHandlersMap,
     Guard,
     Middleware,
     ParametersMap,
@@ -70,7 +70,7 @@ def __init__(
         after_response: Optional[AfterResponseHookHandler] = None,
         before_request: Optional[BeforeRequestHookHandler] = None,
         dependencies: Optional[Dict[str, Provide]] = None,
-        exception_handlers: Optional[Dict[Union[int, Type[Exception]], ExceptionHandler]] = None,
+        exception_handlers: Optional[ExceptionHandlersMap] = None,
         guards: Optional[List[Guard]] = None,
         middleware: Optional[List[Middleware]] = None,
         parameters: Optional[ParametersMap] = None,
diff --git a/starlite/types/callable_types.py b/starlite/types/callable_types.py
--- a/starlite/types/callable_types.py
+++ b/starlite/types/callable_types.py
@@ -1,4 +1,4 @@
-from typing import TYPE_CHECKING, Any, Awaitable, Callable, Union
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar, Union
 
 from .asgi_types import Message, Scope
 from .helpers import SyncOrAsyncUnion
@@ -24,6 +24,8 @@
     WebsocketRouteHandler = Any
     Logger = Any
 
+_ExceptionT = TypeVar("_ExceptionT", bound=Exception)
+
 AfterExceptionHookHandler = Callable[[Exception, Scope, State], SyncOrAsyncUnion[None]]
 AfterRequestHookHandler = Union[
     Callable[[StarletteResponse], SyncOrAsyncUnion[StarletteResponse]], Callable[[Response], SyncOrAsyncUnion[Response]]
@@ -36,7 +38,7 @@
 ]
 BeforeRequestHookHandler = Callable[[Request], Union[Any, Awaitable[Any]]]
 CacheKeyBuilder = Callable[[Request], str]
-ExceptionHandler = Callable[[Request, Exception], StarletteResponse]
+ExceptionHandler = Callable[[Request, _ExceptionT], StarletteResponse]
 Guard = Union[
     Callable[[Request, HTTPRouteHandler], SyncOrAsyncUnion[None]],
     Callable[[WebSocket, WebsocketRouteHandler], SyncOrAsyncUnion[None]],
diff --git a/starlite/utils/exception.py b/starlite/utils/exception.py
--- a/starlite/utils/exception.py
+++ b/starlite/utils/exception.py
@@ -1,5 +1,5 @@
 from inspect import getmro
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union, cast
+from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
 
 from pydantic import BaseModel
 from starlette.exceptions import HTTPException as StarletteHTTPException
@@ -10,12 +10,12 @@
 from starlite.response import Response
 
 if TYPE_CHECKING:
-    from starlite.types import ExceptionHandler
+    from typing import Type
 
+    from starlite.types import ExceptionHandler, ExceptionHandlersMap
 
-def get_exception_handler(
-    exception_handlers: Dict[Union[int, Type[Exception]], "ExceptionHandler"], exc: Exception
-) -> Optional["ExceptionHandler"]:
+
+def get_exception_handler(exception_handlers: "ExceptionHandlersMap", exc: Exception) -> Optional["ExceptionHandler"]:
     """Given a dictionary that maps exceptions and status codes to handler
     functions, and an exception, returns the appropriate handler if existing.
 


Test patch: