How to Validate Dataclass Fields with Python Type Hints

A beginner-friendly helper that checks if instance attributes match their declared type hints using dataclasses and get_type_hints.

Easy Python 3.10+ Aug 9, 2026 Testing & modern typing 13 views 0 copies

Python code

38 lines
Python 3.10+
from typing import Any, TypeVar, get_type_hints
from dataclasses import dataclass

T = TypeVar("T")

@dataclass
class User:
    name: str
    age: int
    email: str

def validate_fields(obj: Any) -> dict[str, bool]:
    """Check if object attributes match declared type hints."""
    hints = get_type_hints(obj.__class__)
    results = {}
    for field, expected_type in hints.items():
        value = getattr(obj, field, None)
        results[field] = isinstance(value, expected_type)
    return results

def print_validation_report(obj: Any) -> None:
    """Display validation results in a readable format."""
    report = validate_fields(obj)
    for field, is_valid in report.items():
        status = "✅ valid" if is_valid else "❌ invalid"
        print(f"{field}: {status}")

if __name__ == "__main__":
    # Test with correct data
    valid_user = User(name="Alice", age=30, email="alice@example.com")
    print("Valid user validation:")
    print_validation_report(valid_user)
    print()

    # Test with incorrect data type (age as string, should fail)
    bad_user = User(name="Bob", age="thirty", email="bob@example.com")
    print("Invalid user validation:")
    print_validation_report(bad_user)

Output

stdout
Valid user validation:
name: ✅ valid
age: ✅ valid
email: ✅ valid

Invalid user validation:
name: ✅ valid
age: ❌ invalid
email: ✅ valid

How it works

This code uses get_type_hints to retrieve the declared type annotations for each field of a dataclass. For each field, it grabs the actual attribute value with getattr and uses isinstance to compare it against the expected type. Because Python evaluates isinstance with a class type, the helper naturally handles primitive types like str and int. This approach is a lightweight alternative to full validation libraries like Pydantic, and it works entirely with the standard library. The dataclass decorator automatically adds a __init__ that stores the given values, so attributes are always present on the instance.

Common mistakes

  • Using `type(value) is expected_type` instead of `isinstance`, which fails for subclass instances.
  • Forgetting that `get_type_hints` requires all annotations to be importable at runtime.
  • Assuming `get_type_hints` works on non-dataclass classes; it works on any class with annotations.
  • Not handling `Optional` types, where `isinstance(value, Optional[int])` would raise TypeError.

Variations

  1. Use a dedicated library like Pydantic for automatic validation with more advanced rules.
  2. Recursively validate nested dataclasses by checking if an attribute is a dataclass instance and calling `validate_fields` on it.

Real-world use cases

  • A quick runtime check before saving user input to a database in a small Flask or FastAPI app.
  • Validating configuration objects loaded from environment variables or config files at startup.
  • A debugging aid in existing codebases to spot mismatched types without rewriting models.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Testing & modern typing

Related tutorials and quizzes for this topic.