- __init__() function
- *args and **kwargs
- Aliases
- and operator
- argparse
- Arrays
- asyncio
- Booleans
- Break statement
- Bytes
- Classes
- Closure
- Code blocks
- Comments
- Conditional statements
- Console
- Context manager
- Data class
- Data structures
- Data types
- Data visualization
- datetime module
- Decorator
- Dictionaries
- Dictionary comprehension
- Django
- Docstrings
- Dunder methods
- Encapsulation
- enum
- enumerate() function
- Equality operator
- Error handling
- Exception handling
- False
- File handling
- Filter()
- Flask framework
- Floats
- Floor division
- For loops
- Formatted strings
- Functions
- Generator
- Globals()
- Greater than operator
- Greater than or equal to operator
- If statement
- in operator
- Indices
- Inequality operator
- Inheritance
- Integers
- Iterator
- JSON
- Lambda function
- len() Function
- Less than operator
- Less than or equal to operator
- List append() method
- List comprehension
- List count()
- List insert() method
- List pop() method
- List reverse() method
- List sort() method
- Lists
- Logging
- map() function
- Match statement
- Math module
- Merge sort
- Min()
- Modules
- Modulo operator
- Multiline comment
- Multiprocessing
- Multithreading
- None
- not operator
- NumPy library
- OOP
- Optional arguments
- or operator
- Override method
- Package manager (pip)
- Packages
- Pandas library
- Parameters
- pathlib module
- Pickle
- Polymorphism
- print() function
- Property()
- Protocol
- Random module
- range() function
- Raw strings
- Recursion
- Reduce()
- Regular expressions
- requests Library
- return statement
- round() function
- Script
- Set comprehension
- Sets
- SQLite
- String decode()
- String find()
- String join() method
- String replace() method
- String split() method
- String strip()
- Strings
- Ternary operator
- time.sleep() function
- True
- try...except statement
- Tuples
- Type casting
- Type hints
- uuid module
- Variables
- Virtual environment
- What is Python?
- While loops
- yield
- Zip function
PYTHON
Python Type Hints: Syntax, Usage, and Examples
Python type hints let you add type information to variables, function parameters, and return values. They make your code easier to read, easier to refactor, and friendlier to tools like linters and autocomplete.
How to Use Type Hints in Python
Type hints look like small labels next to values and function parts. Python ignores them at runtime, but editors and type checkers use them to catch mistakes early.
Learn Python on Mimo
Basic syntax
Here’s the simplest place to start, a variable and a function:
Python
name:str ="Mila"
age:int =28
defgreet(user: str) ->str:
returnf"Hi, {user}!"
name: strmeansnameshould be a stringage: intmeansageshould be an integer> strmeansgreet()returns a string
Common built-in types
You’ll see these constantly:
Python
is_active:bool =True
price:float =19.99
tags:list[str] = ["python","typing"]
settings:dict[str,str] = {"theme":"dark"}
Type hints for functions with multiple parameters
Python
defcalculate_total(price: float, quantity:int, discount:float =0.0) ->float:
return price * quantity * (1 - discount)
Even without reading the function body, you already know what goes in and what comes out.
Optional values with None
A lot of bugs come from assuming a value exists when it doesn’t. Type hints make that situation obvious.
Python
from typingimportOptional
deffind_user(username: str) ->Optional[dict[str,str]]:
if username =="admin":
return {"username":"admin","role":"owner"}
returnNone
That return type means: “You might get a dictionary, or you might get None.”
Union types in modern Python
If your version supports it (Python 3.10+), you can use | instead of Optional:
Python
defparse_id(value: str) ->int |None:
if value.isdigit():
returnint(value)
returnNone
When to Use Type Hints
Type hints help in small scripts, but they really shine when the code grows and other people touch it.
1) When functions start getting reused across your project
Functions tend to live longer than you expect. Your “quick helper” becomes a key piece of logic.
Type hints make the function contract clear, which means fewer “wait, what does this accept?” moments.
2) When you work with data that changes shape
APIs, JSON responses, database rows, user input, config files, all of these can surprise you.
Adding type hints encourages you to handle edge cases early, instead of discovering them in production.
3) When you want better autocomplete and fewer silly bugs
Your editor can suggest the right methods on the right objects. That alone can save a ton of time.
Also, type checkers can catch mistakes like passing a string into a function that expects an int.
4) When you refactor code without breaking everything
Refactoring without types can feel like walking through a dark room barefoot. Something sharp is waiting.
With type hints, you get warnings when changes don’t match what the code expects.
Examples of Type Hints in Python
Let’s build up from everyday code to slightly more structured examples.
Example 1: Typing a function that processes user input
Python
defnormalize_username(raw: str) ->str:
return raw.strip().lower()
username = normalize_username(" Srdjan ")
print(username)# srdjan
A type hint here is simple, but it adds clarity for anyone reading the code.
Example 2: Typing lists and dictionaries
Say you’re storing course progress:
Python
progress:dict[str,int] = {
"Intro to Python":80,
"Functions":55,
"Loops":100
}
completed_lessons:list[str] = ["variables","if statements","for loops"]
Now you can tell at a glance what the collection contains.
Example 3: Typing a function that may return None
This happens constantly with search logic.
Python
from typingimportOptional
defget_discount(code: str) ->Optional[float]:
discounts = {"SAVE10":0.10,"SAVE25":0.25}
return discounts.get(code)
discount = get_discount("SAVE10")
if discountisnotNone:
print(f"Discount: {discount * 100}%")
else:
print("Invalid code")
Type hints push you to handle the None case properly.
Example 4: Typing a class with attributes
Type hints also work inside classes and make your objects easier to understand.
Python
classStudent:
def__init__(self, name: str, score:float) ->None:
self.name:str = name
self.score:float = score
defpassed(self) ->bool:
returnself.score >=60
student = Student("Amara",72.5)
print(student.passed())# True
Even beginners can read this and immediately know what’s going on.
Example 5: Typing a function that returns a tuple
Sometimes returning multiple values is useful, and you can describe that too.
Python
defsplit_full_name(full_name: str) ->tuple[str,str]:
parts = full_name.split(" ",1)
return parts[0], parts[1]
first, last = split_full_name("Mina Jovanovic")
print(first)# Mina
print(last)# Jovanovic
A hint like tuple[str, str] tells you the shape of the return value.
Learn More About Type Hints
Type hints go way beyond int and str. Once you know the basics, you can start typing more complicated patterns without making your code look like a math textbook.
Using typing imports like List, Dict, and Optional
Older versions of Python used List[str] and Dict[str, int] instead of list[str] and dict[str, int].
You’ll still see this in real codebases, especially older ones.
Python
from typingimportList,Dict
names:List[str] = ["Luka","Noor","Sofia"]
scores:Dict[str,int] = {"Luka":95,"Noor":88}
Both styles work, the modern built-in style is just cleaner.
The Any type
Any means “skip type checking here.” It’s useful when you truly don’t know what’s coming in, like raw JSON.
Python
from typingimportAny
data:Any = {"id":123,"items": ["a","b","c"]}
Try not to use Any everywhere, though. Too much of it defeats the point of adding hints.
Callable for functions you pass around
Functions are values in Python, so you can type them too.
Python
from typingimportCallable
defapply_twice(func: Callable[[int],int], value:int) ->int:
return func(func(value))
defdouble(n: int) ->int:
return n *2
print(apply_twice(double,5))# 20
That Callable[[int], int] means: “a function that takes an int and returns an int.”
Type aliases for readability
Some types get long. Aliases keep things clean.
Python
from typingimportOptional
UserId =int
UserName =str
defget_user_name(user_id: UserId) ->Optional[UserName]:
users = {1:"Mira",2:"Kenan"}
return users.get(user_id)
Now the code reads almost like plain English.
Generics like list[T] and dict[K, V]
You’ve already seen generics without naming them. They’re just types with “slots.”
list[str]means list of stringsdict[str, int]means keys are strings, values are integers
This becomes extra useful when you build helper functions that handle many types.
Type hints do not enforce types at runtime
Python won’t stop you from doing this:
Python
age:int ="twenty"
That line runs fine, because Python treats hints as metadata.
Type hints help through tooling, not runtime rules. If you want runtime enforcement, you’d need extra libraries or explicit checks.
Type hints and docstrings work well together
Type hints explain what a function expects, docstrings explain why it exists and how to use it.
Python
defformat_price(amount: float, currency:str) ->str:
"""Format a number as a price string like '€19.99'."""
returnf"{currency}{amount:.2f}"
Hints describe the contract, the docstring adds context.
A quick “real-life” example: typing a small API response
This is the kind of code that benefits from hints fast:
Python
from typingimport TypedDict
classCourse(TypedDict):
title:str
minutes:int
completed:bool
course: Course = {"title":"Intro to CSS","minutes":45,"completed":False}
defcourse_summary(c: Course) ->str:
status ="done"if c["completed"]else"in progress"
returnf"{c['title']} ({c['minutes']} min),{status}"
print(course_summary(course))
TypedDict helps when you use dictionary-shaped data that has a known structure.
Summary
Type hints add readable type information to Python code without changing how the program runs. They make functions and data structures easier to understand, help tools catch mistakes, and make refactoring less stressful as your project grows.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot