Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
TypeSpecで繋ぐ複数プロダクトの型安全 — スキーマ共有による「型契約」の実践_mitsui
Search
UPSIDER, Inc. Tech&Product div.
June 15, 2026
17
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeSpecで繋ぐ複数プロダクトの型安全 — スキーマ共有による「型契約」の実践_mitsui
TSKaigi2026でmitsuiが登壇した資料です。
https://2026.tskaigi.org/talks/23
UPSIDER, Inc. Tech&Product div.
June 15, 2026
More Decks by UPSIDER, Inc. Tech&Product div.
See All by UPSIDER, Inc. Tech&Product div.
最近、評価が難しくなった ── 変わったのは評価項目ではなく、見方と見せ方_Mitsui
upsider_tech
0
7
400超のデータポイントを型で制す — UPSIDERの与信審査エンジンを支えるTypeScriptの「柔軟性」と「結合力」_泉雄介
upsider_tech
0
340
フルスタックTypeScriptで挑む、UPSIDER法人審査システムの再構築_Mitomi
upsider_tech
0
350
TypeScriptの型はAIに届いている か?_shotaro
upsider_tech
1
1k
AI時代におけるプロダクト開発のあり方 を考える_Akari
upsider_tech
0
180
品質を保ちながら、 プロダクトの核に迫るための取り組み_Tanaka Yoshihiro
upsider_tech
0
390
CxOを動かす会社の条件_Akanuma
upsider_tech
0
290
Temporalを用いた Sagaの実践とプロセスモデリング_konnさん
upsider_tech
0
87
決済基盤を作る人から見た、クレカの裏側_Yuya Tanaka
upsider_tech
0
560
Featured
See All Featured
Large-scale JavaScript Application Architecture
addyosmani
515
110k
KATA
mclloyd
PRO
35
15k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
330
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.9k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
180
Automating Front-end Workflow
addyosmani
1370
210k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
180
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
960
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
320
Navigating Weather and Climate Data
rabernat
0
270
Six Lessons from altMBA
skipperchong
29
4.3k
Transcript
TypeSpec で繋ぐ複数プロダクトの型安全 スキーマ共有による「型契約」の実践
TypeSpec って何? Microsoft 製の OSS — API ・データ契約の定義言語 書き味は TypeScript
ライク (model / op / @decorator) 1 つの .tsp → OpenAPI / JSON Schema / Protobuf に変換 @service(#{ title: "Pet Store" }) namespace PetStore; model Pet { id: string; name: string; } @route("/pets") op listPets(): Pet[]; TypeSpec とは
バリデーションも、型に焼き込む TypeSpec は単なる型定義だけじゃない。 正規表現 / 長さ制限 / 値域 といったバリデーションを 型と一体で書ける。
@pattern("^[a-z0-9]{8,}$") scalar UserId extends string; model User { id: UserId; @minLength(8) password: string; @minValue(0) @maxValue(120) age?: int32; } この制約は OpenAPI 経由で Zod にも変換でき、実行時バリデーション としても効く バリデーション
設計ルールも、tsp compile で縛れる TypeSpec の Custom Linter で、組織固有の設計ルールを tsp compile
時に強制できる。 例: 「string scalar には @pattern 必須」をルール化、違反は warning 。 createRule({ name: "require-pattern", severity: "warning", create: (ctx) => ({ scalar: (s) => isStringScalar(s) && !hasPattern(s) && ctx.reportDiagnostic({ target: s }), }), }); bad.tsp:4:8 - warning scalar 'UserId' は string を継承していますが、 @pattern が指定されていません。 > scalar UserId extends string; ^^^^^^ Found 1 warning. 契約の 書き方 だけでなく 設計ルール までガードレールに TypeSpec の拡張性
私たちの使い方 ① プロダクト内 .tsp → tsp compile → OpenAPI YAML
├─ openapi-typescript ─→ TS 型 └─ orval ──────────────→ Zod / API クライアント / MSW モック フロント (React): フォーム validation / API 呼び出し / テストモック バックエンド (Hono): リクエスト validation / レスポンス型 「パスワード 8 文字以上」を TypeSpec で 1 行書けば、FE ・BE ・テスト全部に伝播 使い方 ①
チーム間の型契約 Section
サービス間では、契約が型として存在しない # dev-cross-team サービス A エンジニア 3 分前 @team Webhook
のペイロード、これって 何型ですか? サービス B エンジニア 2 分前 Notion 見たけど 3 ヶ月前から更新止まってる… サービス C エンジニア 1 分前 サンプル JSON から 型を推測しました… 人手で守るしかなく、コンパイラの出番がない サービス間の課題
同期 API も 非同期 Webhook も 同じ言語で書ける 同期 API は
OpenAPI 、非同期メッセージは AsyncAPI / 独自スキーマ、と 別の言語で書くのが普通。 TypeSpec なら 1 つの .tsp に 両方の契約を同居 できる。 // 同期 API(@route + op で表現) @route("/applications") op listApplications(): Application[]; // 非同期 Webhook イベント(model で純粋なデータ契約として表現) model EntityApprovedEvent { type: "entity.approved"; data: ApprovalData; } どちらも 同じ TypeSpec ソースから生成される契約として扱える 独自ポイント
ドキュメントも、契約と一緒に書ける OpenAPI YAML 管理だと 型と説明文が別場所 で並走しがち。 TypeSpec なら /** ...
*/ で 型と同じ場所に 書け、OpenAPI に自動反映される。 /** 法人ユーザー(管理者を含む) */ model User { /** 一意 ID (8 文字以上) */ id: UserId; /** 連絡先メールアドレス */ email: string; } User: type: object description: 法人ユーザー(管理者を含む) properties: id: description: 一意 ID (8 文字以上) email: description: 連絡先メールアドレス 型とドキュメントが 同じソース で管理されるから、説明が古くなりにくい 管理の co-location
私たちの使い方 ② サービス間 上流チームが TypeSpec で書いた契約は npm パッケージとして公開される。 使う側のプロダクトは npm
install + import するだけで取り込める。 上流チーム TypeSpec で契約定義 → ビルド → npm publish → npm レジストリ 📦 @org/contracts 型 / Zod / API クライアント → 使う側のプロダクト npm install + import 別チーム / 別サービス "dependencies": { "@org/contracts": "^1.0.0" } import { EntityApprovedEvent } from '@org/contracts' EntityApprovedEvent.parse(payload) サービス境界を跨ぐ契約を、ドキュメントから「型」へ 使い方 ②
サービス跨ぐ契約変更を、マージ前に検知する 上流が破壊的変更を含む新 version を publish すると、Renovate / Dependabot 等の依存更新 bot
が自動で PR を起票する。 CI checks ✓ lint ✗ typecheck error TS2339: 'oldField' does not exist on 'NewEvent' ❌ Merge blocked マージ前に、契約変更の影響範囲が型エラーとして列挙される 効果
Go 中心のチームでも、TypeSpec で契約を書ける とあるチームの実装は Go ベース。 それでも契約定義は TypeSpec を採用 している。
書き味は TypeScript ライク Go メイン実装でも、契約 DSL の学習コスト は低い 出力は実装言語に依存しない OpenAPI に変換すれば Go の codegen にも 繋がる 複数チームの共通言語 上流 (Go) と下流 (TS) が同じ TypeSpec を見 て契約を共有 契約を書く言語と、サーバーの実装言語は独立して選べる 拡がり
今日の話を 3 行でまとめると 1 API も Webhook も、TypeSpec 1 ファイル
で書ける 同期 API ・非同期イベント・バリデーション・設計ルールまで、同じ DSL に集約 2 書いた契約は npm で配れて、破壊的変更は CI で落ちる サービス境界の契約が package.json の依存として存在し、影響範囲はコンパイルタイムに列挙される 3 TypeScript 以外 の実装言語でも、契約は TypeSpec で書ける 契約 DSL と、サーバーの実装言語は独立して選べる — 異なる技術スタックの共通言語になる 契約は ドキュメント ではなく コード、そして ガードレール へ 総括
スキーマ駆動を、もう一段厳格に。