Skip to main content

Pyright Type Checker

Why Type Checking? (Tier 1: Motivation)

Python is dynamically typed, meaning you can write:

Loading Python environment...

Same variable, three different types. Python doesn't complain—it just changes.

But this causes bugs:

Loading Python environment...

Python runs this fine until you expect result to be a string:

Loading Python environment...

Problem: The bug is in greet(42) call, but the crash is at .upper(). You waste time debugging the wrong place.

Solution: Type hints tell Python what types to expect:

Loading Python environment...

Now the error is caught immediately, before running code.

Benefit: Catch 30–50% of bugs statically (without running code). That's huge.

Source: Verified in intelligence/001-verified-tool-documentation.md


What Are Type Hints? (Tier 1: Learn Syntax)

Type hints are annotations that tell Python what types variables/functions expect.

Function Parameter Types

Loading Python environment...

Read as:

  • x: int — Parameter x should be an integer
  • y: int — Parameter y should be an integer
  • -> int — Function returns an integer

Python 3.13+ Modern Syntax

Python 3.13 introduced new syntax for optional types using | instead of Union:

Loading Python environment...

Read as:

  • data: str | None — Accept string or None (called "union type")
  • -> int — Returns an integer

Older syntax (Python 3.9-3.12) used Union[str, None]. We use 3.13+ syntax because it's cleaner.

Note: Type hints are optional syntax. Python still runs without them. They're for tools like Pyright to catch errors.


Installing Pyright (Tier 1: Direct Command)

Just like Ruff, install via uv:

uv add pyright --dev

Verify installation:

uv run pyright --version

Expected output: pyright 1.1.407 (or similar version)


Running Pyright (Tier 1: Direct Command)

Let's catch a type error!

Create a file types.py:

Loading Python environment...

Run Pyright:

uv run pyright types.py

Expected output:

/path/to/types.py:4:21 - error: Argument of type "Literal[42]" cannot be assigned to parameter "name" of type "str" in function "greet"
"Literal[42]" is not assignable to "str"
1 error, 0 warnings

Read the error:

  • Line 4, column 21: The error location
  • "Literal[42]" cannot be assigned to "str": You passed an integer where a string was expected
  • 1 error: Pyright found one type problem

Fix the code:

Loading Python environment...

Run Pyright again:

uv run pyright types.py

Expected output:

0 errors, 0 warnings, 0 informations

Success! No type errors.

Note: This code demonstrates type checking, not Python programming. You'll learn more about functions and types in Chapter 18.

Source: Verified in intelligence/001-verified-tool-documentation.md


Type Checking Modes (Tier 1: Understand Options)

Pyright has four modes controlling how strict type checking is:

ModeStrictnessUse Case
offNo checkingLegacy code (not recommended)
basicStandard checkingMost projects (default)
standardStricter checkingType-aware projects
strictMaximum safetyType-first projects

Basic mode (default) is usually right. Strict mode catches more potential issues but requires more type hints.

Configure in pyproject.toml:

[tool.pyright]
typeCheckingMode = "standard" # Change to "strict" for more checking
pythonVersion = "3.13"

Common Type Errors (Tier 1: Learn Patterns)

Here are errors Pyright catches:

Error 1: Type Mismatch

Loading Python environment...

Error 2: Return Type Wrong

Loading Python environment...

Error 3: Optional Handling

Loading Python environment...

Fix by checking for None:

Loading Python environment...


Tier 2: Configure Pyright in pyproject.toml

Tell your AI:

I want to configure Pyright for my Python project.
I want:
- Standard type checking (not too strict)
- Python 3.13
- Report missing imports as errors
- Report unknown variable types as warnings

Generate the [tool.pyright] section for pyproject.toml.

AI generates:

[tool.pyright]
typeCheckingMode = "standard"
pythonVersion = "3.13"
reportMissingImports = "error"
reportUnknownVariableType = "warning"

Copy-paste into your pyproject.toml and run:

uv run pyright

Pyright now uses your configuration.

Source: Verified in intelligence/001-verified-tool-documentation.md


Pyright + Zed Integration (Tier 2: Editor Display)

You'll configure Zed to show Pyright type errors inline (next lesson, Lesson 11).

For now, just know: Pyright can run in your editor, showing errors as you type—no need to open terminal.


Type Hints vs. Tests (Tier 1: Understand Relationship)

Type hints and tests are complementary:

ToolCatchesDoesn't Catch
Pyright (type checking)Type mismatchesLogic errors, runtime failures
TestsLogic errors, edge casesType mismatches (without hints)
TogetherMost bugsEdge cases you didn't think of

Good practice: Use both.


Try With AI

Build a complete type-safe Python project integrating UV, Pyright, Ruff, and pytest.

🔍 Explore Type-Safe Project Setup:

"Help me build a type-safe calculator project. Create a UV project calc-app, add Pyright and Ruff as dev dependencies, configure Pyright for Python 3.13 standard mode. Then create calc.py with functions add, subtract, multiply, divide using Python 3.13+ type hints. For divide, handle division by zero by returning None if divisor is zero. Show me complete setup commands and code."

🧪 Test Type Error Detection:

"Create test_errors.py that intentionally breaks type safety: import add from calc.py and call it with add("5", "10") (strings), add(5, None) (None), and store divide(10, 0) result then try math with it (might be None). For each error, show me the exact Pyright message, explain why it caught it, and propose a fix without changing type hints. What's the difference between type errors Pyright catches vs runtime errors that crash?"

🎯 Add Production Dependencies:

"Make the calculator interactive using the rich library for terminal output. Add rich as production dependency (why production not dev?), create main.py with type hints using rich.console.Console to display results, accept user input for two numbers and operation (+/-/*/÷), and handle invalid input gracefully. Show how type hints guide error handling. Then add type-safe validation for when users enter text instead of numbers, handling ValueError."

🚀 Configure Complete Toolchain:

"Set up full toolchain in pyproject.toml: Ruff (line length 88, format on save), Pyright (standard mode, Python 3.13, report missing hints as warnings not errors), and pytest as dev dependency with one test for add() function using type hints. Show me the commands: uv run ruff format ., uv run pyright, uv run pytest. All should pass. Then create a teammate onboarding checklist with environment sync, dependency install, and verification steps."

🔧 Troubleshoot Type Checking Issues:

"I'm seeing these problems with Pyright: (1) Pyright says type error but my code runs fine, (2) Pyright says str | None is invalid syntax, (3) Pyright shows 'LSP not connected' in Zed. For each issue, explain what's happening and give me the fix or workaround. How do I know if a type error is critical or just a warning I can safely ignore?"