Python, checked
before it runs.
A stricter, statically typed superset of Python.
Catch mistakes early. Compile to readable CPython.
curl -fsSL https://typhon.sh/install.sh | shmacOS, Linux and Windows · MIT licensed · In beta
def find_user(uid: int) -> str?:
return "ada" if uid == 1 else None
def greet(user: str) -> None:
print(f"hello, {user}")
def main() -> None:
let user: str? = find_user(1)
greet(user)
main()This value might be None.
greet expects a str. Typhon catches the mismatch before you run the program.
9 greet(user)
^^^^Guard the value to narrow its type..ty in. .py out.One compiler. One binary.CPython 3.13+ in production.A little stricter. A lot clearer.
Good Python habits,
built into the language.
Types, bindings and control flow that say what you mean. Checked before your code becomes Python.
Make the possible explicit.
A plain str cannot hold None. Write str? when it can, then narrow it before use. The compiler keeps the two apart.
Explore the languagedef find_user(uid: int) -> str?:
return "ada" if uid == 1 else None
def greet(user: str) -> None:
print(f"hello, {user}")
def main() -> None:
let user: str? = find_user(1)
if user is not None:
greet(user)
main()Handle every possibility.
Sealed unions make matching exhaustive. Add a new variant, and Typhon points out every match that needs an update.
Explore the languageclass Circle:
radius: float
class Square:
side: float
type Shape = Circle | Square
def area(shape: Shape) -> float:
match shape:
case Circle(radius):
return 3.14 * radius * radius
case Square(side):
return side * sideLet failures be part of the type.
Result makes expected errors visible in a function signature. Propagate them with ? and keep the successful path easy to read.
Explore the languagedef divide(a: int, b: int) -> Result[int, str]:
if b == 0:
return Err("division by zero")
return Ok(a // b)
def calculate() -> Result[int, str]:
let value: int = divide(10, 2)?
return Ok(value * 2)Familiar on the other side.
What you ship is Python.
Typhon checks your source, then gets out of the way. The output is readable CPython 3.13+, with source maps back to your original code.
main.tyYour sourcetycCheck + compilemain.pyPlain Pythondef main() -> None:
let user: str? = find_user(1)
if user is not None:
greet(user)def main() -> None:
user: str | None = find_user(1)
if user is not None:
greet(user)Use Python libraries. Deploy on CPython. No separate Typhon runtime package to install.
Features such as Result generate small Python helpers inside your project. You can read and own that output too.
From first file to everyday work.
One binary.
The whole workflow.
The compiler, formatter, language server and REPL live in tyc. Start a project, check it and build it with the same tool.
tyc init hello
cd hello
tyc check src/
tyc run
tyc build- How is this different from Pyright?
- Typhon adds language features and enforces its rules as it compiles. It writes the Python you deploy.
- Can I use my existing Python libraries?
- Yes. Typhon reads typed library signatures from your environment, with .dty stubs for additional boundaries.
- Can I migrate existing code?
tyc migrateconverts typed Python into Typhon as a starting point.- Is Typhon ready for me?
- Typhon is in beta. Read the compatibility policy before adopting it.