### Apache Airflow version

2.5.1

### What happened

Context: I am attempting to use [TypedDict](https://docs.python.org/3/library/typing.html#typing.TypedDict) objects to maintain the keys used in DAG params in a single place, and check for key names across multiple DAGs that use the params.
This raises an error with `mypy` as `params` expects an `Optional[Dict]`. Due to the invariance of `Dict`, this does not accept `TypedDict` objects.

What happened: I passed a `TypedDict` to the `params` arg of `DAG` and got a TypeError.

### What you think should happen instead

`TypedDict` objects should be accepted by `DAG`, which should accept `Optional[Mapping[str, Any]]`. 

Unless I'm mistaken, `params` are converted to a `ParamsDict` class and therefore the appropriate type hint is a generic `Mapping` type.

### How to reproduce

Steps to reproduce

```Python
from typing import TypedDict

from airflow import DAG
from airflow.models import Param

class ParamsTypedDict(TypedDict):
    str_param: Param

params: ParamsTypedDict = {
    "str_param": Param("", type="str")
}

with DAG(
    dag_id="mypy-error-dag",
    # The line below raises a mypy error
    # Argument "params" to "DAG" has incompatible type "ParamsTypedDict"; expected "Optional[Dict[Any, Any]]"  [arg-type]
    params=params,  
) as dag:
    pass
```

### Operating System

Amazon Linux

### Versions of Apache Airflow Providers

_No response_

### Deployment

Docker-Compose

### Deployment details

_No response_

### Anything else

_No response_

### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)

to render templates as native Python types. If False, a Jinja
        ``Environment`` is used to render templates as string values.
    :param tags: List of tags to help filtering DAGs in the UI.
    :param owner_links: Dict of owners and their links, that will be clickable on the DAGs view UI.
        Can be used as an HTTP link (for example the link to your Slack channel), or a mailto link.
        e.g: {"dag_owner": "https://airflow.apache.org/"}
    :param auto_register: Automatically register this DAG when it is used in a ``with`` block
    """
    _comps = {
        "dag_id",
        "task_ids",
        "parent_dag",
        "start_date",
        "end_date",
        "schedule_interval",
        "fileloc",
        "template_searchpath",
        "last_loaded",
    }
    __serialized_fields: frozenset[str] | None = None
    fileloc: str
    """
    File path that needs to be imported to load this DAG or subdag.
    This may not be an actual file on disk in the case when this DAG is loaded
    from a ZIP file or other DAG distribution format.
    """
    parent_dag: DAG | None = None  
    
    
    def __init__(