The two concepts aren't related any more than any other type-related concepts.

In short, a TypeVar is a variable you can use in type signatures so you can refer to the same unspecified type more than once, while a NewType is used to tell the type checker that some values should be treated as their own type.

Type Variables

To simplify, type variables let you refer to the same type more than once without specifying exactly which type it is.

In a definition, a single type variable always takes the same value.

# (This code will type check, but it won't run.)
from typing import TypeVar, Generic

# Two type variables, named T and R
T = TypeVar('T')
R = TypeVar('R')

# Put in a list of Ts and get out one T
def get_one(x: list[T]) -> T: ...

# Put in a T and an R, get back an R and a T
def swap(x: T, y: R) -> tuple[R, T]:
    return y, x

# A simple generic class that holds a value of type T
class ValueHolder(Generic[T]):
    def __init__(self, value: T):
        self.value = value
    def get(self) -> T:
        return self.value

x: ValueHolder[int] = ValueHolder(123)
y: ValueHolder[str] = ValueHolder('abc')

Without type variables, there wouldn't be a good way to declare the type of get_one or ValueHolder.get.

There are a few other options on TypeVar. You can restrict the possible values by passing in more types (e.g. TypeVar(name, int, str)), or you can give an upper bound so every value of the type variable must be a subtype of that type (e.g. TypeVar(name, bound=int)).

Additionally, you can decide whether a type variable is covariant, contravariant, or neither when you declare it. This essentially decides when subclasses or superclasses can be used in place of a generic type. PEP 484 describes these concepts in more detail, and refers to additional resources.

Addendum: Python 3.12 generic parameter lists

Starting in Python 3.12, the following syntax has been available to declare type variables.

def get_oneT -> T: ...

def swapT, R -> tuple[R, T]: ...

class ValueHolder[T]:
    def __init__(self, value: T): ...
    def get(self) -> T: ...

These declarations are equivalent to those above, but now the type variables are only defined in type signatures within their functions/classes, rather than being stored in regular Python variables. The Python 3.12 release notes contain a summary, as well as links to more-detailed documentation.

NewType

A NewType is for when you want to declare a distinct type without actually doing the work of creating a new type or worry about the overhead of creating new class instances.

In the type checker, NewType('Name', int) creates a subclass of int named "Name."

At runtime, NewType('Name', int) is not a class at all; it is actually the identity function, so x is NewType('Name', int)(x) is always true.

from typing import NewType

UserId = NewType('UserId', int)

def get_user(x: UserId): ...

get_user(UserId(123456)) # this is fine
get_user(123456) # that's an int, not a UserId

UserId(123456) + 123456 # fine, because UserId is a subclass of int

To the type checker, UserId looks something like this:

class UserId(int): pass

But at runtime, UserId is basically just this:

def UserId(x): return x

There's almost nothing more than that to a NewType at runtime. In Python 3.8.1, its implementation was almost exactly as follows:

def NewType(name, type_):
    def identity(x):
        return x
    identity.__name__ = name
    return identity
Answer from jirassimok on Stack Overflow
๐ŸŒ
Python documentation
docs.python.org โ€บ 3 โ€บ library โ€บ typing.html
typing โ€” Support for type hints
3 weeks ago - Generic classes implicitly inherit from Generic. For compatibility with Python 3.11 and lower, it is also possible to inherit explicitly from Generic to indicate a generic class: from typing import TypeVar, Generic T = TypeVar('T') class LoggedVar(Generic[T]): ...
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
Create a TypeVar bound to TypedDict - Python Help - Discussions on Python.org
June 27, 2025 - Iโ€™m trying to create a TypeVar that is limited to TypedDict. When I try TV = TypeVar("TV", bound=TypedDict), I see type checker (mypy) error: Variable "typing.TypedDict" is not valid as a type [valid-type]. When I lookโ€ฆ
Discussions

python - What is the difference between TypeVar and NewType? - Stack Overflow
TypeVar and NewType seem related but I'm not sure when I'm supposed to use each or what the difference is at runtime and statically. More on stackoverflow.com
๐ŸŒ stackoverflow.com
Should I use a TypeVar?
Typevars are useful if you want to annotate generic classes and function. In your case, you don't need it. More on reddit.com
๐ŸŒ r/learnpython
11
7
January 28, 2024
How to parameterize a TypeVar by another TypeVar
Hi! I have the following Protocol: from typing import Protocol, TypeVar ValueType = TypeVar("ValueType") # Protocol for types, that provide a [] operator for reading and writing. class In... More on github.com
๐ŸŒ github.com
2
1
February 28, 2024
I would like the param to be a class type and return an instance of that class, how do I use TypeVar so that there are Type Hints like this
# Like this, but it doesn't work. :( def foo(param:Type[T])->T:... class ABaseClass:... # if T is ABaseClass def foo(param:Type[ABaseClass]) -> ABaseClass:... # I've tried this too and it still doesn't work def foo(param:T)->T.__args__[0]: More on discuss.python.org
๐ŸŒ discuss.python.org
0
September 12, 2023
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
Generics, Type[T], and TypeVarTuple - Python Help - Discussions on Python.org
September 4, 2023 - With non-variadic generics, I can write something like the following: from typing import Generic, Type, TypeVar T = TypeVar("T") class Example(Generic[T]): atype: Type[T] def __init__(self, atype: Type[T]): self.atype = atype def get_value(self) -> T: # I can use self.atype in here ...
๐ŸŒ
Medium
medium.com โ€บ pythoneers โ€บ understanding-typevar-in-python-f78e5108471d
Understanding TypeVar in Python. A Quick Guide to Generics, Bestโ€ฆ | by Harshit Singh | The Pythoneers | Medium
January 8, 2025 - Unlike Go, which prioritizes structural ... flexibility for those who prefer dynamic typing. TypeVar will enable developers to write type-safe, reusable, and flexible code....
๐ŸŒ
Piccolo-orm
piccolo-orm.com โ€บ blog โ€บ advanced-type-annotations-using-python-s-type-var
Advanced type annotations using Python's TypeVar - Piccolo Blog
January 6, 2023 - import decimal from typing import TypeVar Number = TypeVar("Number", int, float, decimal.Decimal) def double(value: Number) -> Number: return value * 2
Top answer
1 of 2
222

The two concepts aren't related any more than any other type-related concepts.

In short, a TypeVar is a variable you can use in type signatures so you can refer to the same unspecified type more than once, while a NewType is used to tell the type checker that some values should be treated as their own type.

Type Variables

To simplify, type variables let you refer to the same type more than once without specifying exactly which type it is.

In a definition, a single type variable always takes the same value.

# (This code will type check, but it won't run.)
from typing import TypeVar, Generic

# Two type variables, named T and R
T = TypeVar('T')
R = TypeVar('R')

# Put in a list of Ts and get out one T
def get_one(x: list[T]) -> T: ...

# Put in a T and an R, get back an R and a T
def swap(x: T, y: R) -> tuple[R, T]:
    return y, x

# A simple generic class that holds a value of type T
class ValueHolder(Generic[T]):
    def __init__(self, value: T):
        self.value = value
    def get(self) -> T:
        return self.value

x: ValueHolder[int] = ValueHolder(123)
y: ValueHolder[str] = ValueHolder('abc')

Without type variables, there wouldn't be a good way to declare the type of get_one or ValueHolder.get.

There are a few other options on TypeVar. You can restrict the possible values by passing in more types (e.g. TypeVar(name, int, str)), or you can give an upper bound so every value of the type variable must be a subtype of that type (e.g. TypeVar(name, bound=int)).

Additionally, you can decide whether a type variable is covariant, contravariant, or neither when you declare it. This essentially decides when subclasses or superclasses can be used in place of a generic type. PEP 484 describes these concepts in more detail, and refers to additional resources.

Addendum: Python 3.12 generic parameter lists

Starting in Python 3.12, the following syntax has been available to declare type variables.

def get_oneT -> T: ...

def swapT, R -> tuple[R, T]: ...

class ValueHolder[T]:
    def __init__(self, value: T): ...
    def get(self) -> T: ...

These declarations are equivalent to those above, but now the type variables are only defined in type signatures within their functions/classes, rather than being stored in regular Python variables. The Python 3.12 release notes contain a summary, as well as links to more-detailed documentation.

NewType

A NewType is for when you want to declare a distinct type without actually doing the work of creating a new type or worry about the overhead of creating new class instances.

In the type checker, NewType('Name', int) creates a subclass of int named "Name."

At runtime, NewType('Name', int) is not a class at all; it is actually the identity function, so x is NewType('Name', int)(x) is always true.

from typing import NewType

UserId = NewType('UserId', int)

def get_user(x: UserId): ...

get_user(UserId(123456)) # this is fine
get_user(123456) # that's an int, not a UserId

UserId(123456) + 123456 # fine, because UserId is a subclass of int

To the type checker, UserId looks something like this:

class UserId(int): pass

But at runtime, UserId is basically just this:

def UserId(x): return x

There's almost nothing more than that to a NewType at runtime. In Python 3.8.1, its implementation was almost exactly as follows:

def NewType(name, type_):
    def identity(x):
        return x
    identity.__name__ = name
    return identity
2 of 2
0

NewType() accepts an unique type parameter. To specialize the function for different types for static typing, you only need a TypeVar here.

Example: Read https://dev.to/decorator_factory/typevars-explained-hmo

Find elsewhere
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ should i use a typevar?
r/learnpython on Reddit: Should I use a TypeVar?
January 28, 2024 -

In my code I have an alias for a type and mypy is happy about it.

NumberedPaths = list[tuple[str, str]]

Should I use TypeVar instead? Is there any better way to define a new type?

๐ŸŒ
Python
typing.python.org โ€บ en โ€บ latest โ€บ spec โ€บ generics.html
Generics โ€” typing documentation
Use the new generic class syntax in Python 3.12 and higher. Include a Protocol base class parameterized with type variables. This approach also marks the class as a protocol - see generic protocols for more information. Include a generic base class parameterized with type variables. ... from typing import TypeVar, Generic from logging import Logger T = TypeVar('T') class LoggedVar(Generic[T]): def __init__(self, value: T, name: str, logger: Logger) -> None: self.name = name self.logger = logger self.value = value def set(self, new: T) -> None: self.log('Set ' + repr(self.value)) self.value = new def get(self) -> T: self.log('Get ' + repr(self.value)) return self.value def log(self, message: str) -> None: self.logger.info('{}: {}'.format(self.name, message))
๐ŸŒ
Medium
gabrielgomes61320.medium.com โ€บ python-development-best-practices-using-typevar-1b88db0c1473
Python Development Best Practices โ€” Using TypeVar | by Gabriel Gomes, PhD | Medium
February 18, 2024 - The answer to this question is by using TypeVar. This class, which is provided by the typing Python library, allows us to define new type variables.
๐ŸŒ
Mypy
mypy.readthedocs.io โ€บ en โ€บ stable โ€บ generics.html
Generics - mypy 1.19.1 documentation
Here is the same example using the old syntax (required for Python 3.11 and earlier, but also supported on newer Python versions): from typing import TypeVar, Generic T = TypeVar('T') # Define type variable "T" class Stack(Generic[T]): def __init__(self) -> None: # Create an empty list with items of type T self.items: list[T] = [] def push(self, item: T) -> None: self.items.append(item) def pop(self) -> T: return self.items.pop() def empty(self) -> bool: return not self.items
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
I would like the param to be a class type and return an instance of that class, how do I use TypeVar so that there are Type Hints like this - Python Help - Discussions on Python.org
September 12, 2023 - # Like this, but it doesn't work. :( def foo(param:Type[T])->T:... class ABaseClass:... # if T is ABaseClass def foo(param:Type[ABaseClass]) -> ABaseClass:... # I've tried this too and it still doesn't work def foo(param:T)->T.__args__[0]:
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ what does t = typevar("t", int, float) mean?
r/learnpython on Reddit: What does T = TypeVar("T", int, float) mean?
November 4, 2022 -

The following code runs fine, but mypy raises:

example_types.py:29: error: Argument 1 to "only_int" has incompatible type "float"; expected "int"

Why does mypy infer T to be a float? Naively I expected T = TypeVar("T", int, float) to mean T can be either int or float, and then mypy to complain that MyTuple(4, 2.3) takes inputs of different types.

from typing import TypeVar, Generic


T = TypeVar("T", int, float)


class MyTuple(Generic[T]):
    def __init__(self, first: T, second: T):
        self.first: T = first
        self.second: T = second

    def get_first(self) -> T:

        return self.first

    def get_second(self) -> T:

        return self.second


def only_int(a: int):

    assert isinstance(a, int)


num = MyTuple(4, 2.3)

a = num.get_first()
only_int(a)
๐ŸŒ
Pydantic
docs.pydantic.dev โ€บ 2.0 โ€บ usage โ€บ types โ€บ typevars
Type and TypeVar - Pydantic
from typing import TypeVar from pydantic import BaseModel Foobar = TypeVar('Foobar') BoundFloat = TypeVar('BoundFloat', bound=float) IntStr = TypeVar('IntStr', int, str) class Model(BaseModel): a: Foobar # equivalent of ": Any" b: BoundFloat # equivalent of ": float" c: IntStr # equivalent of ": Union[int, str]" print(Model(a=[1], b=4.2, c='x')) #> a=[1] b=4.2 c='x' # a may be None print(Model(a=None, b=1, c=1)) #> a=None b=1.0 c=1
๐ŸŒ
Medium
medium.com โ€บ @jaberi.mohamedhabib โ€บ python-generics-enhancing-readability-and-reusability-with-typevar-a1cfa566d0ac
Python Generics: Enhancing Readability and Reusability with TypeVar | by JABERI Mohamed Habib | Medium
March 2, 2024 - To refine this scenario, Python generics, empowered by the typing module, offer an elegant and structured solution. Let's reimagine the _safe_timezone function, introducing generics: from typing import TypeVar, Union T = TypeVar('T', str, float, None) TimezoneType = TypeVar('TimezoneType', bound=Union[Timezone, FixedTimezone]) def _safe_timezone(obj: T = None) -> TimezoneType: # Your logic here pass
๐ŸŒ
Alex Korablev
alexkorablev.com โ€บ generics-in-python
Alex Korablev โ€“ Using typing.Generic in Python
February 18, 2022 - Letโ€™s fix it. Here is my first approach. It is a naive use of generics in Python. # file name: type_cast_2.py #... TV = tp.TypeVar('TV') class DoSomethingWithA(tp.Generic[TV]): _class: tp.Type[TV] = A def do(self) -> TV: return self._class() class DoSomethingWithB(DoSomethingWithA): _class = B
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
Confusing way to use TypeVar - Python Help - Discussions on Python.org
October 13, 2022 - in file1.py from typing import TypeVar T = TypeVar('T', ???) class A: def __init__(self, model: T): self.model = model def func(self, param: T): pass in file2.py @dataclass class BModel: x: str โ€ฆ
๐ŸŒ
Python.org
discuss.python.org โ€บ typing
How to write a function that accepts either a TypeVar or a list of that TypeVar? - Typing - Discussions on Python.org
January 15, 2024 - Iโ€™ve got a function where an argument is a dict[str, int | list[int]], and I want to replace int with a type variable. In other words, dict holds non-sequence objects or lists of those objects, but all basal elements are of the same type. V = TypeVar("V") # if we had type negation, would be bound to !list def baz(val: Union[list[V], V]) -> V: if isinstance(val, list): return val[0] return val baz(1) baz([1]) mypy & pyright both point out that, in baz([1]), debugme.py:7: not...
๐ŸŒ
Python.org
discuss.python.org โ€บ typing
Non-uniqueness of TypeVar on Python versions <3.12 causes resolution issues
October 28, 2023 - In Python 3.12, the new Generic / TypeVar syntax allows us to do this: class Foo[T, U]: type: T info: U class Bar[T](Foo[str, T]): test: T Which, for older versions is functionally equivalent to this: from typing import Generic, TypeVar FooT = TypeVar('FooT') FooU = TypeVar('FooU') class Foo(Generic[FooT, FooU]): type: FooT info: FooU BarT = TypeVar('BarT') class Bar(Foo[str, BarT], Generic[BarT]): test: BarT Key point being that each TypeVar is unique to the cla...
๐ŸŒ
Gaohongnan
gaohongnan.com โ€บ computer_science โ€บ type_theory โ€บ 05-typevar-bound-constraints.html
Bound and Constraint in Generics and Type Variables โ€” Omniverse
Concrete: T = TypeVar("T", bound=BaseModel) means T can be any type that is a subclass of BaseModel (from pydantic). In Pythonโ€™s type hinting system, you can define a type variable that restricts which types can be used in place of it by specifying an upper bound.