05 / 05

What is the difference between Optional[X], Union[X, Y], and the newer X | Y syntax (PEP 604)?

Difficulty: 5/10
Optional, Union, PEP 604, Type Hint Syntax

Optional means X or None; Union allows multiple types; X | Y is the concise PEP 604 syntax

Optional[X] is exactly equivalent to Union[X, None]. It signals that a value can be X or None. Union[X, Y] means the value can be either X or Y, and can be extended to more types. Before Python 3.10, you had to import these from typing. PEP 604 introduced the | operator, so you can write X | Y directly, and it works at runtime with isinstance and issubclass. The | syntax is cleaner and avoids the import, but it requires Python 3.10+. The typing.Optional and typing.Union forms are still valid and necessary for older versions. One subtlety: Optional[X] does not mean the parameter is optional; it means the value can be None. A parameter with a default value is optional in the calling sense, which is a different concept.

  1. 1

    Optional[X] == Union[X, None]. Use it when None is a valid value.

  2. 2

    Union[X, Y] allows any of the listed types. Order does not matter for type checking.

  3. 3

    X | Y (PEP 604) is the modern syntax, available in 3.10+. It works with isinstance and issubclass.

  4. 4

    You can mix: int | None, str | bytes, and even nested unions.

  5. 5

    Trade-off: the | syntax is concise but not available in older codebases. typing.Optional is more explicit for readers unfamiliar with PEP 604.

  6. 6

    Common mistake: thinking Optional[X] means the parameter has a default. It does not.

  7. 7

    Common mistake: using X | Y in Python 3.9 or earlier, which raises TypeError at runtime when evaluating the annotation.

  8. 8

    Version note: PEP 604 landed in 3.10. For 3.7-3.9, use from future import annotations to postpone evaluation, or stick to typing.Union and typing.Optional.

javascript

Scenario Questions

0-2 years experience

  1. 1How do you annotate a function that returns a string or None?
  2. 2What does Optional[int] mean?

2-5 years experience

  1. 1You need to support Python 3.9 and want to use the | syntax. What do you do?
  2. 2You have a parameter that can be int, float, or str. How do you annotate it?

5-8 years experience

  1. 1You are migrating a codebase from typing.Union to PEP 604. What are the risks and how do you automate it?
  2. 2You need runtime type checking with isinstance against a union. How does that work in 3.10+?

8+ years experience

  1. 1Design a typing compatibility layer for a library that supports Python 3.8 through 3.12, handling Union, Optional, and PEP 604 transparently.
  2. 2Explain how PEP 604 interacts with typing.get_type_hints, forward references, and from __future__ import annotations in a multi-version codebase.

Follow-up Questions

  • How do you write a union type for Python 3.9 and earlier?
  • What is the runtime behavior of int | str in Python 3.10+?
Share

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.