# Python Typing Module

The `typing` module provides runtime support for type hints. The most fundamental support consists of the types `Any`, `Union`, `Callable`, `TypeVar`, and `Generic`. For full specification, please see PEP 484.

## Importing the Module

```python
import typing
```

## Common Types

Since Python 3.9, many built-in collection types (like `list`, `dict`, `tuple`) support subscription (e.g., `list[int]`). However, the `typing` module provides aliases for these and other types, which are necessary for older Python versions or for more complex typing scenarios.

### List, Dict, Tuple, Set

```python
from typing import List, Dict, Tuple, Set

# List of integers
numbers: List[int] = [1, 2, 3]

# Dictionary with string keys and float values
prices: Dict[str, float] = {'apple': 1.5, 'banana': 2.0}

# Tuple with specific types
person: Tuple[str, int] = ('Alice', 30)

# Set of strings
tags: Set[str] = {'red', 'green', 'blue'}
```

### Optional and Union

*   `Optional[T]`: Equivalent to `Union[T, None]`.
*   `Union[T1, T2]`: Indicates that a value can be either type T1 or T2.

```python
from typing import Optional, Union

def greet(name: Optional[str] = None) -> str:
    if name is None:
        return "Hello, stranger"
    return f"Hello, {name}"

def process(value: Union[int, str]) -> None:
    if isinstance(value, int):
        print(f"Processing integer: {value}")
    else:
        print(f"Processing string: {value}")
```

### Any

`Any` is a special type indicating that a value can be of any type. Static type checkers will treat every type as being compatible with `Any` and `Any` as being compatible with every type.

```python
from typing import Any

def do_something(x: Any) -> Any:
    return x
```

## Type Aliases

You can define aliases for complex types to make code more readable.

```python
from typing import List, Tuple, Dict

Vector = List[float]
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]

def connect(server: Server) -> None:
    pass
```

## NewType

`NewType` creates distinct types that are treated differently by the type checker but are identical at runtime.

```python
from typing import NewType

UserId = NewType('UserId', int)

def get_user_name(user_id: UserId) -> str:
    return "User"

# Type checker ensures we pass a UserId, not just any int
user_a = UserId(12345)
get_user_name(user_a) 

# get_user_name(12345) # This would be a type error
```

## Callable

`Callable` is used to type hints for functions or other callable objects. The syntax is `Callable[[Arg1Type, Arg2Type], ReturnType]`.

```python
from typing import Callable

def apply_func(x: int, func: Callable[[int], int]) -> int:
    return func(x)

def square(x: int) -> int:
    return x * x

print(apply_func(5, square)) # Output: 25
```

## Generics and TypeVar

`TypeVar` is used to define generic types.

```python
from typing import TypeVar, Sequence

T = TypeVar('T')      # Declare type variable

def first(seq: Sequence[T]) -> T:
    return seq[0]

print(first([1, 2, 3])) # Output: 1 (inferred as int)
print(first('abc'))     # Output: 'a' (inferred as str)
```

[[programming/python/python]]