# Type Hints and Dataclasses for Cleaner Pipeline Code

> Use type hints and dataclasses to make records explicit, catch bugs before runtime, and keep pipeline functions small and testable.

- Source: https://akshaythakare.com/notes/python/type-hints-and-dataclasses
- Topic: Python
- Level: beginner
- Reading time: 2 min
- Tags: python, typing, dataclasses, code-quality
- Updated: 2026-10-11

## Why bother in data code?

Pipelines pass the same records through many functions. Dictionaries with unknown keys make every step guess. A typed record says exactly what a row contains.

```python
from dataclasses import dataclass
from datetime import date
from decimal import Decimal

@dataclass(frozen=True)
class OrderLine:
    order_id: str
    sku: str
    qty: int
    unit_price: Decimal
    business_date: date

    @property
    def net(self) -> Decimal:
        return self.unit_price * self.qty
```

`frozen=True` makes instances immutable, so a transform cannot silently change its input.

## Type hints on functions

```python
from collections.abc import Iterable, Iterator

def only_valid(lines: Iterable[OrderLine]) -> Iterator[OrderLine]:
    for line in lines:
        if line.qty != 0:
            yield line
```

Hints do nothing at runtime. A checker such as **mypy** or **pyright** reads them and reports mistakes like passing a `str` where a `date` is expected.

## Parse at the edge, trust inside

```python
def parse(row: dict[str, str]) -> OrderLine:
    return OrderLine(
        order_id=row["order_id"],
        sku=row["sku"],
        qty=int(row["qty"]),
        unit_price=Decimal(row["unit_price"]),
        business_date=date.fromisoformat(row["business_date"]),
    )
```

Convert raw strings into typed records **once**, where data enters. Every function after that can rely on the types.

> **Note: Dataclass or Pydantic?**
>
> Dataclasses are standard library and fast. Pydantic adds runtime validation and good error messages. It is useful at API boundaries, but it is a dependency.
