mypy vs Pyright: CIに適したPythonの型チェッカーはどちら?
mypyはPythonのリファレンス型チェッカーで、PyrightはVS CodeのPylanceも支える高速で厳格なチェッカーです。
mypyはPython向けのオリジナルで広く使われている静的型チェッカーであり、タイピング標準とともにメンテナンスされています。Pyright (Microsoft製) はTypeScriptで実装されたチェッカーで、強力な推論、速度、Pylance経由のVS Codeとの緊密な統合で知られています。
mypy vs Pyright at a glance
| mypy | Pyright | |
|---|---|---|
| 速度 | 中程度 | 高速 (インクリメンタル、watch mode) |
| 推論 | 良好 | 強力 |
| エディタ統合 | plugin/LSP経由 | ネイティブ (Pylance/VS Code) |
| 厳格さの制御 | 粒度の細かいflag | 粒度が細かい、strict mode |
| リファレンスの地位 | タイピングのリファレンス実装 | 独立、広く使われている |
| 言語サーバー | なし | あり。VS CodeのPylanceを支える |
| 実装言語 | Python、mypycでコンパイル | TypeScript |
| 設定 | mypy.ini、setup.cfg、pyproject.toml | pyrightconfig.json、pyproject.toml |
CIにおいて
どちらも型エラーで失敗するCIゲートとして動作します。Pyrightは一般的に高速で強力な推論を持ち、mypyが見逃す問題を捉えられることがあり、素早いフィードバックを与えます。エディタ (Pylance) とCIで同じチェッカーを走らせると結果に一貫性が保たれます。mypyはリファレンス実装であり、公式のタイピングセマンティクスに最も近く、既存の設定やstubの大きな蓄積があります。カバレッジを最大化するために両方を走らせるプロジェクトもあります。
# mypy, checking what Pyright checks by default
mypy --check-untyped-defs src/
# or go all the way
mypy --strict src/
# Pyright at its default (already checks everything)
pyright src/
# Pyright at basic, if the default is too much to adopt at once
pyright --level basic src/pipeline向けの選択
速度とVS Code/Pylanceとのエディタ一致が欲しい: Pyright。リファレンスチェッカーとタイピング標準への最も近い一致が欲しい: mypy。結果が再現的になるよう、CIでバージョンと厳格さのflagを固定しましょう。
- Joins versus unions. When merging types across branches, mypy joins to a common supertype while Pyright forms a union. Pyright documentation states that joins discard valuable type information and lead to many false positive errors.
- Literal preservation.
(1, "stop")gives PyrightLiteral["stop"]and gives mypystr. If you use literal types for state machines or discriminated unions, mypy widening them costs you the checking you wanted. - Variable declarations. mypy treats a first assignment as an implicit declaration; Pyright infers a union across assignments. mypy behaviour is the more surprising of the two when a variable legitimately holds different types over its life.
速度: 定説はいま争点になっている
Pyrightのドキュメントは、大規模コードベースでmypyより3〜5倍速いと述べており、これが長年の通説でした。2026年においては、より慎重に扱う価値があります。
- この数字は、mypyがmypycでコンパイルされたバイナリとして配布されるようになる前、また1.18の最適化作業より前のものです。この作業はmypy自身のコードベース上で大きな改善をもたらしました。
- 最近の独立した比較では、現行のmypyはPyrightと互角で、場合によっては上回るとされています。
- どちらも最新の参入者には大きく後れを取っています。Metaのpyreflyは2026年5月に安定版1.0に到達し、両者に対して10〜50倍を報告しています。Astralのtyはまだアルファです。
pluginはPyrightにできない唯一のこと
これはこの比較で最も明確な二者択一です。mypyはpluginに対応し、Pyrightにplugin機構はなく、メンテナは今後も導入しないと述べています。
- Djangoのモデルは属性を動的に生成します。
django-stubsとそのmypy pluginがなければ型チェッカーはそれを追えず、Pyrightはそのpluginを読み込めません。 - SQLAlchemyの宣言的モデルも同じ形の問題を抱えます。
- コードベースがどちらかに依存しているなら、この比較の他の部分が何を言おうと、mypyのplugin対応は好みではなく必須要件です。
どちらかをCIで動かす
# mypy
- run: pip install mypy
- run: mypy --strict src/
# Pyright, with machine-readable output for annotations
- run: pip install pyright
- run: pyright --outputjson src/ > pyright.json
# Adopting gradually: fail only on files already clean
- run: mypy src/ --strict --exclude "src/legacy/.*"両方使えるか?
はい。大規模なコードベースの一部はそうしていますが、見返りは思ったより狭いものです。PylanceによるエディタでのPyrightと、CIのゲートとしてのmypyという分担はよくある形です。入力中はPyrightの推論を得つつ、正しさを強制する場所ではmypyのplugin対応が効くからです。
- 代償は、一致していなければならない2つの設定を維持すること、あるいはエディタとCIが食い違うのを受け入れることです。
- 食い違いは仮定の話ではありません。上記の推論の違いは、同じコードに対して実際に異なる判定を生みます。
- 多くのチームにとって、きちんと設定した1つのチェッカーは、おおよそ設定した2つに勝ります。
Benchmark on your repository before choosing
Build-tool benchmarks published by vendors use repositories chosen to show a difference. Yours is the only one that matters, and both a cold and a warm measurement are needed because CI mostly runs cold.
# cold: no cache, the CI condition
rm -rf node_modules/.cache dist && time <tool> build
# warm: the local development condition
time <tool> build
# and the one people forget: incremental after a one-line change
echo "// touch" >> src/index.ts && time <tool> buildThe verdict
高速なチェックとエディタとの一致が欲しい: Pyright。タイピング標準に沿ったリファレンスチェッカーが欲しい: mypy。どちらも堅実なCIゲートになります - バージョンと厳格さを固定し、最大のカバレッジのために両方を走らせることも検討しましょう。
よくある質問
なぜPyrightはmypyより多くのエラーを報告するのですか?
--check-untyped-defs か --strict を渡さない限り注釈のない関数を飛ばしますが、Pyrightは既定ですべてのコードを検査し、mypyが Any と仮定する箇所で戻り値の型を推論します。mypy --check-untyped-defs を実行すると差は大きく縮まります。Pyrightはmypyより速いですか?
Pyrightはmypyのpluginに対応していますか?
django-stubs やSQLAlchemyのmypy pluginに依存しているなら、その要件だけでこの比較の結論が決まります。