### 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)

aggressively when using positive weight values. This is useful when you
        have multiple dag run instances and prefer to have each dag complete
        before starting upstream tasks of other dags.  When set to
        ``absolute``, the effective weight is the exact ``priority_weight``
        specified without additional weighting. You may want to do this when
        you know exactly what priority weight each task should have.
        Additionally, when set to ``absolute``, there is bonus effect of
        significantly speeding up the task creation process as for very large
        DAGs. Options can be set as string or using the constants defined in
        the static class ``airflow.utils.WeightRule``
    :param queue: which queue to target when running this job. Not
        all executors implement queue management, the CeleryExecutor
        does support targeting specific queues.
    :param pool: the slot pool this task should run in, slot pools are a
        way to limit concurrency for certain tasks
    :param pool_slots: the number of pool slots this task should use (>= 1)
        Values less than 1 are not allowed.
    :param sla: time by which the job is expected to succeed. Note that
        this represents the ``timedelta`` after the period is closed. For
        example if you set an SLA of 1 hour, the scheduler would send an email
        soon after 1:00AM on the ``2016-01-02`` if the ``2016-01-01`` instance
        has not succeeded yet.
        The scheduler pays special attention for jobs with an SLA and
        sends alert
        emails for SLA misses. SLA misses are also recorded in the database
        for future reference. All tasks that share the same SLA time
        get bundled in a single email, sent soon after that time. SLA
        notification are sent once and only once for each task instance.
    :param execution_timeout: max time allowed for the execution of
        this task instance, if it goes beyond it will raise and fail.