type
type Name = value creates a TypeAliasType. The value is not evaluated until you ask for __value__, so an alias can refer to names defined later — even itself.
type Vector = list[float]
type Pair[T] = tuple[T, T]
type Nums[T: (int, float)] = list[T]
type Tree = list[Tree | int]
Demo
log = [] def make(value): log.append('evaluated') return value type Alias = make(42) before = list(log) Alias.__value__ Alias.__value__ (before, log, Alias.__value__)
In the lazy tab, before is empty: creating the alias ran nothing. Three __value__ reads produce a single log entry, because the value is computed once and cached. With 1e400 the code shows inf, which is not a Python name — and the NameError appears only at the first __value__ access, not on the type line. In the generic tab, Pair[...] builds a parameterised alias holding whatever you passed; nothing validates it against T at runtime — that is the type checker’s job.
Syntax slots
| Name | Type | Required | Description |
|---|---|---|---|
| Name | identifier | yes | The alias name. Bound like an assignment in the current scope. |
| [T, ...] | type params | no | Type parameters, making the alias generic: T, T: bound, T: (A, B), *Ts, **P. Since 3.13 a default: T = int. |
| expression | expression | yes | The aliased type. Evaluated lazily, on first access of Name.__value__, then cached. |
Common patterns
type JSON = dict[str, JSON] | list[JSON] | str | int | float | bool | None
from collections.abc import Hashable type Index[K: Hashable] = dict[K, list[int]]
type UserId = int def load(uid: UserId) -> dict[str, str]: ...
from typing import TypeAlias Vector: TypeAlias = list[float]
Examples
Pitfalls
type Vector = list[float] isinstance([1.0], Vector)
type Vector = list[float] isinstance([1.0], list)
from typing import TypeAlias Tree: TypeAlias = list[Node] class Node: pass
type Tree = list[Node] class Node: pass Tree.__value__
type Vector = list[float] Vector == list[float]
type Vector = list[float] Vector.__value__ == list[float]
When to use
- Naming a long or repeated type hint (unions, nested generics, callables)
- Recursive types and forward references — no quotes needed
- Generic aliases: type Result[T] = T | Error
- Code that must run on Python 3.11 or older → Name: TypeAlias = ... (typing)
- A distinct type for type checkers (UserId must not accept any int) → typing.NewType
- Anything you need to instantiate or check with isinstance() → use the class itself
Notes
FAQ
The type statement (3.12+) creates a TypeAliasType whose value is evaluated lazily, supports type parameters directly and allows forward and recursive references without quotes. X: TypeAlias = ... (3.10+) is a normal assignment with a marker annotation: evaluated at once, so forward references must be strings. typing.TypeAlias is deprecated since 3.12 in favour of the type statement.