From the documentation - Union Type:

A union object holds the value of the | (bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared to typing.Union.

This use of | was added in Python 3.10. Hence the proper way to represent more than one return data type is:

def foo(client_id: str) -> list | bool:

For earlier versions, use typing.Union:

from typing import Union


def foo(client_id: str) -> Union[list, bool]:

But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."

>>> def foo(a: str) -> list:
...     return "Works"
... 
>>> foo(1)
'Works'

As you can see I am passing an int value and returning a str. However the __annotations__ will be set to the respective values.

>>> foo.__annotations__ 
{'return': <class 'list'>, 'a': <class 'str'>}

Please go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??

Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.

Answer from Bhargav Rao on Stack Overflow
Top answer
1 of 4
1051

From the documentation - Union Type:

A union object holds the value of the | (bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared to typing.Union.

This use of | was added in Python 3.10. Hence the proper way to represent more than one return data type is:

def foo(client_id: str) -> list | bool:

For earlier versions, use typing.Union:

from typing import Union


def foo(client_id: str) -> Union[list, bool]:

But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."

>>> def foo(a: str) -> list:
...     return "Works"
... 
>>> foo(1)
'Works'

As you can see I am passing an int value and returning a str. However the __annotations__ will be set to the respective values.

>>> foo.__annotations__ 
{'return': <class 'list'>, 'a': <class 'str'>}

Please go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??

Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.

2 of 4
184

Python 3.10 or newer: Use |. Example for a function which takes a single argument that is either an int or str and returns either an int or str:

def func(arg: int | str) -> int | str:
    #         ^^^^^^^^^     ^^^^^^^^^ 
    #        type of arg   return type

Python 3.5 - 3.9: Use typing.Union:

from typing import Union

def func(arg: Union[int, str]) -> Union[int, str]:
    #         ^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^ 
    #           type of arg         return type

For the special case of X | None you can use Optional[X].

๐ŸŒ
Python.org
discuss.python.org โ€บ documentation
How should we mark up multiple types in a type field? - Documentation - Discussions on Python.org
March 11, 2024 - When using the :type: and :rtype: directives, how do we want to mark up multiple types? Currently, weโ€™re using a bar (|), similar to how youโ€™d annotate a union of types: :param p: A parameter that takes an int or a float argument. :type p: int | float :param other: Possibly a path.
๐ŸŒ
Reddit
reddit.com โ€บ r/python โ€บ how to use type hints for multiple return types in python
r/Python on Reddit: How to Use Type Hints for Multiple Return Types in Python
October 31, 2023 - For that, there is the Optional type hint ... Quite frequently, raising an exception is better than returning a sentinel None. ... First time reading about sentinel values. I knew the concept but never put a name to it. Thank you :) ... I personally, prefer -> typing.Union[int, None]: in this case for return types. Optional doesnโ€™t sit well with me for return types. But, for Pythons that support it, just -> int | None:
๐ŸŒ
Real Python
realpython.com โ€บ python-type-hints-multiple-types
How to Use Type Hints for Multiple Return Types in Python โ€“ Real Python
March 8, 2024 - In this tutorial, you'll learn to specify multiple return types using type hints in Python. You'll cover working with one or several pieces of data, defining type aliases, and type checking with a third-party static type checker tool.
๐ŸŒ
Molssi
education.molssi.org โ€บ type-hints-pydantic-tutorial โ€บ chapters โ€บ TypeHintsInPython.html
Type Hints in Python โ€” Python Type Hints, Dataclasses, and Pydantic
The correct way to define multiple valid types is to define a Union of them, just like the concept of โ€œunionโ€ from set theory. In this context, โ€œunionโ€ simply means โ€œany of the items in this collection are valid. Weโ€™ll need the native Python library called typing to access the Union ...
๐ŸŒ
Python documentation
docs.python.org โ€บ 3 โ€บ library โ€บ typing.html
typing โ€” Support for type hints
The first argument to Annotated must be a valid type. Multiple metadata elements can be supplied as Annotated supports variadic arguments.
๐ŸŒ
Better Stack
betterstack.com โ€บ community โ€บ guides โ€บ scaling-python โ€บ python-type-hints
A Complete Guide to Python Type Hints | Better Stack Community
Function annotations are the most common use case for type hints. They let you specify what types a function expects and what it returns, making your code more self-documenting and easier to understand for both humans and tools. ... from typing import List, Optional, Union def repeat_string(s: str, times: int) -> str: """Repeat a string multiple times.""" return s * times def get_first_item(items: List[int]) -> Optional[int]: """Return the first item or None if empty.""" return items[0] if items else None def process_value(value: Union[int, str]) -> str: """Process either an int or a string.""" if isinstance(value, int): return f"Number: {value * 2}" else: return f"String: {value.upper()}"
๐ŸŒ
Mypy
mypy.readthedocs.io โ€บ en โ€บ stable โ€บ cheat_sheet_py3.html
Type hints cheat sheet - mypy 1.19.1 documentation
# For most types, just use the name of the type in the annotation # Note that mypy can usually infer the type of a variable from its value, # so technically these annotations are redundant x: int = 1 x: float = 1.0 x: bool = True x: str = "test" x: bytes = b"test" # For collections on Python 3.9+, the type of the collection item is in brackets x: list[int] = [1] x: set[int] = {6, 7} # For mappings, we need the types of both keys and values x: dict[str, float] = {"field": 2.0} # Python 3.9+ # For tuples of fixed size, we specify the types of all the elements x: tuple[int, str, float] = (3, "yes
Find elsewhere
๐ŸŒ
Python
peps.python.org โ€บ pep-0484
PEP 484 โ€“ Type Hints | peps.python.org
The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. This pattern is used frequently in builtin modules and types.
๐ŸŒ
Geek Python
geekpython.in โ€บ type-hinting-in-python
Python Type Hints: Functions, Return Values, Variable
April 19, 2024 - Well, it looks like but Python or specifically interpreter completely ignores the type hints as this is not its purpose. The type of arguments was decided in the runtime that is why no error is thrown, however, you may see a warning in your IDE or code editor. In this section, youโ€™ll learn how to annotate multiple return types for a single value of alternative types and multiple values of different types.
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ type hinting functions with multipe return types including none
r/learnpython on Reddit: Type hinting functions with multipe return types including None
August 12, 2022 -

Hey guys

I often write functions where the wanted returned type is, let's say, bool, but it could also return None. The returned bool can be True, but it will never be False:

def is_odd(number):
    if number % 2 == 0:
        return True

print(is_odd(4))

(obviously this function could have been written differently, like returning the evaluation directly, but it's an example of what could be long functions where this is not an option).

With type hinting, I know I can define multiple return types. But since I am looking for a bool value, and not so much the None value, what is the most Pythonic to type hint the function?

Should it always reflect all the possible returned types, including None, like this?

def is_odd(number: int) -> bool | None:
    if number % 2 == 0:
        return True

Or is this okay?

def is_odd(number: int) -> bool:
    if number % 2 == 0:
        return True
๐ŸŒ
Python Tutorial
pythontutorial.net โ€บ home โ€บ python basics โ€บ python type hints
Python Type Hints
April 2, 2025 - def add(x, y): return x + yCode language: Python (python) The numbers can be integers or floats. You can use the module to set type hints for multiple types.
๐ŸŒ
Python
docs.python.org โ€บ 3.9 โ€บ library โ€บ typing.html
typing โ€” Support for type hints โ€” Python 3.9.24 documentation
To the type checker this signals ... anything (we want this to be as fast as possible). ... The @overload decorator allows describing functions and methods that support multiple different combinations of argument types....
๐ŸŒ
Real Python
realpython.com โ€บ courses โ€บ type-hints-multiple-return-types
Using Type Hints for Multiple Return Types in Python โ€“ Real Python
September 26, 2024 - In this video course, you'll learn how to define multiple return types using type hints in Python. This course covers working with single or multiple pieces of data, defining type aliases, and performing type checking using a third-party static type checker tool.
๐ŸŒ
Python
docs.python.org โ€บ 3.8 โ€บ library โ€บ typing.html
typing โ€” Support for type hints โ€” Python 3.8.20 documentation
The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method).
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ type-hints-in-python
Type Hints in Python - GeeksforGeeks
May 3, 2025 - Type hints are a feature in Python that allow developers to annotate their code with expected types for variables and function arguments.
๐ŸŒ
Open Water Foundation
learn.openwaterfoundation.org โ€บ owf-learn-python โ€บ lessons โ€บ type-hints โ€บ type-hints
Type Hints - OWF Learn Python
If the function return type indicated by the type hint only indicates the str type, then an IDE might complain with a message like expecting str but None is returned. The following example illustrates how to avoid the warning by specifying multiple return types:
๐ŸŒ
Pybites
pybit.es โ€บ articles โ€บ code-better-with-type-hints-part-3
Code Better With Type Hints โ€“ Part 3 - Pybites
September 20, 2022 - Type hints are even more useful in combination with a dataclass: from dataclasses import dataclass @dataclass class Point: x: int y: int ยท Although Python does not prevent you from initializing a Point instance with the wrong types, so Point("1", "2") will not throw an error, the dataclass decorator will use the type hint information for some internal magic like auto-generating a __init__(self, x: int, y: int) method with the right type annotations for each parameter.
๐ŸŒ
Towards Data Science
towardsdatascience.com โ€บ home โ€บ latest โ€บ type hints in python โ€“ everything you need to know in 5 minutes
Type Hints in Python - Everything You Need To Know In 5 Minutes | Towards Data Science
January 30, 2025 - Basically, it allows you to specify multiple possible data types for variables and return values. Hereโ€™s the implementation of the previous function: ... The function can now both accept and return a list of integers or floats, warning-free.