Slide 1

Slide 1 text

1 次世代リンターで探る、 tsgo 時代における型認識カスタムルールの現実解 髙橋 佑太 / Yuta Takahashi TSKaigi 2026 #tskaigi_leverages

Slide 2

Slide 2 text

2 ⾃⼰紹介:髙橋 佑太 / Yuta Takahashi ● 株式会社メドレー 医科診療所プロダクト開発室 AI推進グループ テックリード ○ クラウド診療システムCLINICSを開発 ● TypeScript歴8年ほど ○ TSは主にWebフロントエンドで利⽤ ● Go/Rust の実務経験なし X: @Wakekupsloth Zenn: https://zenn.dev/yuta_takahashi はじめに

Slide 3

Slide 3 text

3 本トークのテーマ これから来る typescript-go 時代に、 型認識カスタムルール(Type-Aware Linting) とどう向き合っていくか はじめに

Slide 4

Slide 4 text

4 1. 導⼊: 型認識カスタムルールとは

Slide 5

Slide 5 text

5 実例 1: 標準の型認識ルール — @typescript-eslint/no-floating-promises 式の型が thenable かを⾒て検出: 1. 導⼊: 型認識カスタムルールとは

Slide 6

Slide 6 text

6 実例 2: 型認識カスタムルール — eslint-plugin-neverthrow/must-use-result `Result` が処理されずに残るのを検出: 1. 導⼊: 型認識カスタムルールとは

Slide 7

Slide 7 text

7 現在の型認識リントは typescript-eslint が担う typescript-eslint の型認識ルール: ● ESLint プラグインとして JS / TS で書く ● 必要なときだけ parser services 経由で TypeChecker を引いて型情報をもとに診断 ● AST だけで動くリントより実⾏時間は伸びやすい 1. 導⼊: 型認識カスタムルールとは

Slide 8

Slide 8 text

8 2. tsgo 時代の変化

Slide 9

Slide 9 text

9 typescript-go / tsgo ● TypeScript コンパイラの Go / native 実装 ● 型チェック‧ビルド‧エディタ向け処理を⾼速化する取り組み(10x faster) ● TypeScript 7.0 Beta として公開されており既に利⽤可能 ○ `npm install -D @typescript/native-preview@beta` 2. tsgo 時代の変化

Slide 10

Slide 10 text

10 tsgo では型情報へのアクセス境界が変わる ● 型チェック本体は Go 実装 / ネイティブプロセス側へ移る ● JS / TS で書かれたESLintカスタムルールは、従来の parser services 経由では tsgo 側の型情報を参 照できない 2. tsgo 時代の変化

Slide 11

Slide 11 text

11 tsgo 時代の問い: 型認識カスタムルールをどこで動かすのか 1. 既存の typescript-eslint に残す ○ JS 版 TypeScript Compiler API をtsgoと併⽤で使い続ける ■ npm install -D typescript@npm:@typescript/typescript6 ○ 既存の配布‧設定‧エディタ統合を使える 2. Goやその他の型解析基盤の可能性 ○ tsgo によって型チェック本体が Go バックエンドへ移るなら、型認識カスタムルールも Goで運⽤できる可能性がある ○ 次世代リンターはJS 版 TypeScript Compiler APIに依存しない 型認識ルールに取り組んでいる ○ 実⾏速度の⾯で恩恵を受けることができることがモチベーション 2. tsgo 時代の変化

Slide 12

Slide 12 text

12 3. 型認識カスタムルールの 実⾏基盤⽐較

Slide 13

Slide 13 text

13 Oxlint:tsgolint をバックエンドにして型認識リントに対応 ● 構成: Rust 製 CLI + tsgolint ● 型解析基盤: typescript-go(`oxc-project/tsgolint` 経由) ● 標準の型認識ルール: @typescript-eslint 互換の型認識ルールを59件持つ ● 型認識カスタムルール: 未対応 3. 型認識カスタムルールの実⾏基盤⽐較 https://oxc.rs/

Slide 14

Slide 14 text

14 Rslint :Go 製リンターとして型認識リントに対応 ● 構成: `typescript-eslint/tsgolint` fork の Go 製CLI ● 型解析基盤: `typescript-go`(直接組み込み) ● 標準の型認識ルール: @typescript-eslint 互換の型認識ルールを129件持つ ● カスタムルール: 未対応 ● 型認識カスタムルール: 未対応 3. 型認識カスタムルールの実⾏基盤⽐較 https://rslint.rs/

Slide 15

Slide 15 text

15 Biome:独⾃型推論で型認識リントに対応 ● 構成: Rust製 CLI ● 型解析基盤: Biotype(独⾃型推論) ● 標準の型認識ルール: `types` domain の16ルール ● カスタムルール: GritQL プラグイン ● 型認識カスタムルール: ⾮対応 3. 型認識カスタムルールの実⾏基盤⽐較 https://biomejs.dev/

Slide 16

Slide 16 text

16 型認識リントの対応状況 凡例: ○ 安定提供 / △ 部分対応‧整備中 / × 現⾏の公開 API では不可 3. 型認識カスタムルールの実⾏基盤⽐較 実⾏基盤 標準の型認識ルール 型認識カスタム ルール 型解析基盤 typescript-eslint ○ 133件 ○ 対応 TypeScript Compiler API (JS 版) Oxlint + tsgolint △ `@typescript-eslint` 型認識 ルール 59件実装済み × ⾮対応 typescript-go(tsgolint 経由) Rslint △ 129件(内97件が完全実装済み) × ⾮対応 typescript-go(直接組み込み) Biome △ `types` domain 16 件(安定推 奨外) × ⾮対応 Biotype(独⾃型推論)

Slide 17

Slide 17 text

17 3. 型認識カスタムルールの実⾏基盤⽐較 https://github.com/web-infra-dev/rslint/issues/32 すぐ検証できそうなのでやってみることに Rslintの型認識カスタムルール対応に関する検討案

Slide 18

Slide 18 text

18 4. Go バックエンドルール PoC

Slide 19

Slide 19 text

19 Rslint にパッチを当てて型認識カスタムルールを実装する PoC で確かめること: ● 型認識カスタムルールをGo バックエンドルールとして「書けるか」 実装⽅針: ● Rslint 本体に Go で組み込む ● Rslint は git submodule で取り込み、PoC 差分は patch として管理 ● patchしたRslintをビルドして実⾏ 検証リポジトリ: https://github.com/YTakahashii/typed-lint-go-backend-poc 4. Go バックエンドルール PoC

Slide 20

Slide 20 text

20 題材ルール: no-discarded-contract-value ● 任意の契約型の戻り値を、式⽂として捨てることを検出 ● 検出対象の型名やパッケージはRslint Configから設定 4. Go バックエンドルール PoC

Slide 21

Slide 21 text

21 no-discarded-contract-value の実装構造 段階 1. 型判定 ● 対象の式の型を取り、`Promise` や `await` 後の `T` を取り出して、 その `T` が契約型に該当するかを判断。 段階 2. 値のハンドリング判定 4. Go バックエンドルール PoC コード PoC 判定 `await cancelOrder(id)` NG (捨てている) `void await cancelOrder(id)` NG (明⽰的に捨てている) `return cancelOrder(id)` OK (呼び出し元へ渡す) `const result = await cancelOrder(id)` OK (保持)

Slide 22

Slide 22 text

22 Rslint 実装: internal/rulesに追加 4. Go バックエンドルール PoC

Slide 23

Slide 23 text

23 Rslint 実装: 診断対象の式と型を取り出す(⼀部抜粋) 4. Go バックエンドルール PoC

Slide 24

Slide 24 text

24 Rslint 実装: 契約型かどうかを判定する(⼀部抜粋) 4. Go バックエンドルール PoC

Slide 25

Slide 25 text

25 PoC 実装結果: 診断デモ 4. Go バックエンドルール PoC

Slide 26

Slide 26 text

26 5. PoC の解釈と運⽤リスク

Slide 27

Slide 27 text

27 運⽤モデルの差: 書けるだけでは代替できない 5. PoC の解釈と運⽤リスク 観点 ESLint プラグイン Go バックエンドルール プラグイン合成 設定に複数のプラグインを宣⾔して並⾏運⽤で きる 単⼀バイナリのみ。プラグイン合成モデルはな い 型 API 安定性 TypeScript Compiler API / parser services に依 存 typescript-go の internal API に依存 API 追従 typescript-eslint 側が吸収 バックエンド API の変化を⾃前 shim で追従 エディタ統合 既存経路(VSCode の eslint extension など)を 利⽤できる 専⽤バイナリをエディタ体験へ組み込む設計が 別に要る Goバックエンドでのカスタムルール⾃前実装は 運⽤負荷が⾮常に⾼い

Slide 28

Slide 28 text

28 運⽤リスク補⾜: internal API 依存 PoC は typescript-go の internal API に依存: ● `GetAwaitedType` などの unexported api は shim で呼び出している ● 内部実装の変更を⾃前で追従し続ける必要がある Go バックエンドルールを採⽤するなら、この追従コストを織り込んだ運⽤設計が必要。 5. PoC の解釈と運⽤リスク

Slide 29

Slide 29 text

29 6. 現実解: 振り分けと設計での削減

Slide 30

Slide 30 text

30 現実解: 型認識カスタムリントとの向き合い⽅を再考する 6. 現実解: 振り分けと設計での削減

Slide 31

Slide 31 text

31 PoC 題材の再設計: 型判定から API 規約へ PoC では型情報を⽤いて判定(再掲): 6. 現実解: 振り分けと設計での削減 プロジェクト固有の型ルールをAPI規約に落とし込めないか考える

Slide 32

Slide 32 text

32 PoC 題材の再設計: 型判定から API 規約へ AST に出す 3 つの規約: ● import パス / ファイル名で API 境界を識別する ● 消費関数で扱い⽅を固定する(TypeScriptの型で縛る) ● ファクトリ関数で インタフェースを強制する ● 6. 現実解: 振り分けと設計での削減

Slide 33

Slide 33 text

33 PoC 題材の再設計: 型判定から API 規約へ AST に出す 3 つの規約: ● import パス / ファイル名で API 境界を識別する ● 消費関数で扱い⽅を固定する(TypeScriptの型で縛る) ● ファクトリ関数で インタフェースを強制する 6. 現実解: 振り分けと設計での削減

Slide 34

Slide 34 text

34 参考:`runUsecase` / `defineUsecase` のシグネチャ runUsecase内で⾮同期タスクの実⾏をハンドルする形式を想定 ※このインターフェースを推奨しているわけではなく、あくまで参考例として受け取ってください Appendix

Slide 35

Slide 35 text

35 7. 注視していきたい動向とまとめ

Slide 36

Slide 36 text

36 TypeScript API 側の動向: programmatic API ● 7.0 Beta 時点: 安定 API は未提供。早くても 7.1 以降 ● Node.js プログラムから別プロセスの `tsgo --api` に stdio / IPC で問い合わせる構成 7. 注視していきたい動向とまとめ

Slide 37

Slide 37 text

37 次世代リンターのカスタムプラグインの動向 7. 注視していきたい動向とまとめ リンター 型解析基盤 拡張 API の現状 / 構想 Oxlint typescript-go(tsgolint 経由) JS プラグインは型情報未対応。Wasm プラグインは GitHub Discussion 上で議論中 Rslint typescript-go(直接組み込み) カスタムルールの公開‧配布モデルは未対応。 AST + 型公開 / AST のみ / 本体組み込みが議論中 Biome Biotype(独⾃型推論) GritQL プラグインは型情報⾮対応。RFC #1762 では、 GritQL で絞り込んだノードに対し JS / TS 層から Biotype の型 API を呼べるハイブリッドプラグインが議論中

Slide 38

Slide 38 text

38 ubugeeei/corsa-bind: Oxlint JS Plugin から tsgo へアクセスする試み 7. 注視していきたい動向とまとめ ● Oxlint JS Plugin から `tsgo` の型情報へ問い合わせを実証したOSS ● JS / TS で カスタム型認識ルールを 書くことができる ● `@corsa-bind/napi` が Node.js から Rust 製 native addon を呼ぶ ● Rust 側が `tsgo --api` を起動し、stdio で型情報を問い合わせる Oxlint JS Pluginからtsgoへアクセスする仕組みの概要

Slide 39

Slide 39 text

39 ubugeeei/corsa-bind: Oxlint JS Plugin から tsgo へアクセスする試み 7. 注視していきたい動向とまとめ ● 馴染みあるparser services / TypeChecker API でカスタ ムルールを記述する例 (https://github.com/ubugeeei/corsa-bind#type-awar e-oxlint 出典)

Slide 40

Slide 40 text

40 まとめ: 型認識ルールは 3 つの選択肢に振り分ける 現時点での答えは、まず標準の型認識ルールで⾜りるかを⾒ること。 残った型認識カスタムルールは、段階的に振り分ける: • 設計で型認識カスタムルールを不要にする (型設計で表す / 現状の AST だけで判定する / API 設計を変えて AST に表す) • 既存の typescript-eslint に残す (速度要件がない場合は最も安定の選択肢) • 速度優先で Go 専⽤バイナリ運⽤へ (速度がボトルネック、かつ API 整備を待てない領域) エコシステムの進化を注視しつつ 特に新規開発で型認識カスタムルールが欲しくなった際は⼀度⽴ち⽌まり、 API 設計で解決できないかを考えたい。 7. 注視していきたい動向とまとめ

Slide 41

Slide 41 text

41 Appendix

Slide 42

Slide 42 text

42 ⼀次情報: TypeScript / tsgo API - TypeScript 7.0 Beta 公式ブログ https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/ - TypeScript Native Preview 公式ブログ https://devblogs.microsoft.com/typescript/announcing-typescript-native-previews/ - `microsoft/typescript-go` repository https://github.com/microsoft/typescript-go - `microsoft/typescript-go` API の⾻格を⽰す PR https://github.com/microsoft/typescript-go/pull/711 Appendix

Slide 43

Slide 43 text

43 ⼀次情報: typescript-eslint - typescript-eslint Rules 公式ドキュメント https://typescript-eslint.io/rules/ - typescript-eslint Typed Rules 公式ドキュメント https://typescript-eslint.io/developers/custom-rules/#typed-rules - `typescript-eslint/no-floating-promises` 公式ドキュメント https://typescript-eslint.io/rules/no-floating-promises/ Appendix

Slide 44

Slide 44 text

44 ⼀次情報: Oxlint - Oxlint Type-Aware Linting 公式ドキュメント https://oxc.rs/docs/guide/usage/linter/type-aware.html - Oxlint Type-Aware Linting Alpha 公式ブログ https://oxc.rs/blog/2025-12-08-type-aware-alpha.html - `oxc-project/tsgolint` repository https://github.com/oxc-project/tsgolint - `oxc-project/tsgolint` Architecture https://github.com/oxc-project/tsgolint/blob/main/ARCHITECTURE.md - `oxc-project/tsgolint` Benchmarks https://github.com/oxc-project/tsgolint/blob/main/benchmarks/README.md Appendix

Slide 45

Slide 45 text

45 ⼀次情報: Oxlint - Oxlint JS Plugins 公式ドキュメント https://oxc.rs/docs/guide/usage/linter/js-plugins - Oxlint Writing JS Plugins 公式ドキュメント https://oxc.rs/docs/guide/usage/linter/writing-js-plugins - Oxc GitHub Discussion: Oxlint Plugins Written In JavaScript(Wasm プラグイン検討コメントを含む) https://github.com/oxc-project/oxc/discussions/10342 - Oxc GitHub Discussion: Oxlint Custom JS Plugins ESLint Compat https://github.com/oxc-project/oxc/discussions/14862 - Oxc GitHub Discussion: Oxlint JS Plugins compatibility https://github.com/oxc-project/oxc/discussions/20245 Appendix

Slide 46

Slide 46 text

46 ⼀次情報: Rslint - `web-infra-dev/rslint` repository https://github.com/web-infra-dev/rslint - Rslint `@typescript-eslint` 互換ルール⼀覧 https://rslint.rs/rules/?group=%40typescript-eslint - `web-infra-dev/rslint` issue: Rslint Custom Rule Support https://github.com/web-infra-dev/rslint/issues/32 Appendix

Slide 47

Slide 47 text

47 ⼀次情報: Biome v2 / Biotype - Biome v2 — codename: Biotype(公式ブログ) https://biomejs.dev/blog/biome-v2/ - Biome v2.0 beta(公式ブログ) https://biomejs.dev/blog/biome-v2-0-beta/ - Biome v2.1(公式ブログ‧noFloatingPromises ~85% ⾔及) https://biomejs.dev/blog/biome-v2-1/ - Biome partners with Vercel to improve type inference(公式ブログ) https://biomejs.dev/blog/vercel-partners-biome-type-inference/ - Roadmap 2025 and Biome 2.0(公式ブログ) https://biomejs.dev/blog/roadmap-2025/ Appendix

Slide 48

Slide 48 text

48 ⼀次情報: Biome v2 / Biotype - Biome Linter Domains 公式ドキュメント https://biomejs.dev/linter/domains/ - Biome Linter Plugins 公式ドキュメント https://biomejs.dev/linter/plugins/ - Biome GritQL 公式リファレンス https://biomejs.dev/reference/gritql/ - Biome GitHub Discussion: RFC: Biome Plugins Proposal https://github.com/biomejs/biome/discussions/1762 Appendix

Slide 49

Slide 49 text

49 ⼀次情報: corsa-bind - `ubugeeei/corsa-bind` repository https://github.com/ubugeeei/corsa-bind - `corsa-bind` README(`@corsa-bind/napi` と `corsa-oxlint` の位置づけ) https://github.com/ubugeeei/corsa-bind#type-aware-oxlint - `corsa-oxlint` package README https://github.com/ubugeeei/corsa-bind/tree/main/src/bindings/nodejs/typescript_oxlint Appendix