Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
TypeSpecで繋ぐ複数プロダクトの型安全 — スキーマ共有による「型契約」の実践_mitsui
Search
UPSIDER, Inc. Tech&Product div.
June 15, 2026
41
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.
なぜレスポンスボディを読み切るのか - Go 1.27で進化した net/http のコネクション再利用メカニズム_Ryu
upsider_tech
1
170
エンジニアはどこまで越境するべきか_Take
upsider_tech
9
3.5k
『⽌めない』を設計する 制約の中で、事業の根幹を⽀える判断_terry
upsider_tech
0
45
English for Shy Engineers
upsider_tech
0
140
時価総額から逆算する、日々開発価値_ PL/BSで読み解くエンジニアリング貢献_Kinsho
upsider_tech
1
210
最近、評価が難しくなった ── 変わったのは評価項目ではなく、見方と見せ方_Mitsui
upsider_tech
0
42
400超のデータポイントを型で制す — UPSIDERの与信審査エンジンを支えるTypeScriptの「柔軟性」と「結合力」_泉雄介
upsider_tech
0
790
フルスタックTypeScriptで挑む、UPSIDER法人審査システムの再構築_Mitomi
upsider_tech
0
420
TypeScriptの型はAIに届いている か?_shotaro
upsider_tech
1
1.8k
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
730
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
Leo the Paperboy
mayatellez
10
2.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
409
67k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Tell your own story through comics
letsgokoyo
1
1.1k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
540
Marketing to machines
jonoalderson
1
5.8k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
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 と、サーバーの実装言語は独立して選べる — 異なる技術スタックの共通言語になる 契約は ドキュメント ではなく コード、そして ガードレール へ 総括
スキーマ駆動を、もう一段厳格に。