Skip to main content

Type Hints for Python Developers

5‑Minute Tour with Pyrefly

Goal: In five minutes you’ll know how Python’s static type system infersdefines, and composes types—and you’ll have copy‑paste snippets to start using right away.

If you are new to Python, check out our Python Types for Newcomers guide.

Python's type system allow you to annotate variables so you, your teammates and your type checker can find bugs before you run your code. Think of it as documentation that's automatically validated and will help your IDE help you.

TL;DR

  • Catch bugs before running the code.
  • Improve editor autocomplete & refactors.
  • Turn your code into living documentation.

Types with Inference

Static analyzers can often infer types from your code—no annotations required. Pyrefly takes this a step further.

Python's built-in types can be used to write many simple type hints.


Where Inference Shines ✨

  • Constant assignments (answer = 42 -> int)
  • List/tuple/dict literals with uniform elements (names = ["A", "B"] -> list[str])
  • Return types if parameter types are annotated:

When to Add Hints

  • Public APIs (library or service boundaries)
  • Mixed collections (list[int | str])
  • Callable signatures (decorators, callbacks)

Define Types Inline

The Basics

Python's built-in types can be used to write many simple type hints.


Functions

Defining the parameter and return types for a function doesn't just help prevent bugs, but it makes it easier to navigate in other files. You don't always need to define a return type - we'll do our best to infer it for you! We can't always get it right and an explicit return type will help your IDE navigate faster and more accurately.


Advanced Types

Composing Types

The real power comes from composing smaller pieces into richer shapes.

Unions & Optional


Generics

Generics allow you to define reusable functions and classes that work with multiple types. This feature enables you to write more flexible and adaptable code.


Protocols

Protocols enable structural typing, which allows you to define interfaces without explicit inheritance. This feature helps you write more modular and composable code.


Structural Types

Python also employs a structural type system, often referred to as "duck typing." This concept is based on the idea that if two objects have the same shape or attributes, they can be treated as being of the same type.

Dataclasses

Dataclasses allow you to create type-safe data structures while minimizing boilerplate.


TypedDict

Typed dictionaries enable you to define dictionaries with specific key-value types. This feature lets you bring type safety to ad-hoc dictionary structures without major refactoring.


Overloads

Overloads allow you to define multiple function signatures for a single function. Like generics, this feature helps you write more flexible and adaptable code.


Typing Features, PEPS available in each Python Version

Feature (click PEP for details)What it adds / looks likeIntroduced in
PEP 484 -- Core type hints & typing moduledef add(a: int, b: int) -> int:3.5
PEP 526 -- Variable annotationscount: int = 03.6
PEP 563 -- from __future__ import annotations (lazy eval)Annotations stored as strings3.7 (future‑flag)
PEP 544 -- Protocols (structural typing)class Jsonable(Protocol): ...3.8
PEP 589 -- TypedDictclass User(TypedDict): ...3.8
PEP 586 -- Literal typesdef log(level: Literal["info","warn"]): ...3.8
PEP 591 -- Final qualifierTOKEN: Final[str] = "..."3.8
PEP 585 -- Built‑in genericslist[int], dict[str, Any]3.9
PEP 593 -- Annotatedx: Annotated[int, "units=px"]3.9
PEP 604 -- Union syntaxint | None3.10
PEP 612 -- ParamSpec / Concatenatedecorator‑safe generics3.10
PEP 613 -- TypeAlias qualifierVector: TypeAlias = list[float]3.10
PEP 647 -- TypeGuard for narrowingdef is_str(x) -> TypeGuard[str]: ...3.10
PEP 655 -- Required / NotRequired for TypedDictoptional vs. mandatory keys3.11
PEP 646 -- Variadic generics (TypeVarTuple, Unpack)tensor shapes, 2‑D arrays, ...3.11
PEP 673 -- Self typefluent APIs: def set(...) -> Self:3.11
PEP 681 -- dataclass_transform helperlibraries like Pydantic, attrs3.11
PEP 695 -- Class‑level generics syntaxclass Box[T]: ...3.12
PEP 649 -- New deferred‑eval algorithm (replaces PEP 563)becomes the default3.13
PEP 698 -- @override decoratorflag intentional overrides3.13 (planned)

Key Highlights Summary:

  • Inference: Python's static analyzers can infer types from your code, reducing the need for explicit annotations. This feature enhances code readability and helps catch bugs early.
  • Defining Types: You can define types inline using Python's built-in types, which aids in documentation and improves IDE support.
  • Advanced Types: The guide covers advanced concepts like composing types, using unions and optionals, generics, protocols, and structural types like dataclasses and TypedDict.
  • Practical Examples: The guide includes examples of functions, generic classes, structural typing with protocols, and more, demonstrating how to apply these concepts in real-world scenarios.