Slide 1

Slide 1 text

TypeScript で Platform SDK を作る技術 Building a Platform SDK in TypeScript TSKaigi 2026: #TSKaigi #tskaigi_righttouch 樋口 彰 / テイラー株式会社 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript

Slide 2

Slide 2 text

自己紹介 樋口 彰 / Akira HIGUCHI 略歴: リクルート Android / Java バックエンド / React atama plus Python バックエンド / Angular / Vue / Electron テイラー株式会社(現職) Tailor Platform™ SDK の設計と実装 GitHub / X: @toiroakr TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 2

Slide 3

Slide 3 text

Platform SDK SDK(Software Development Kit) アプリケーションを開発するためのツール群 本発表における Platform SDK インフラ定義 DB スキーマ、ワークフロー、認証、ホスティング バックエンドのビジネスロジック TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 3

Slide 4

Slide 4 text

Platform TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 4

Slide 5

Slide 5 text

SDK 以前 Terraform / CUE による宣言的な IaC Platform のインフラレイヤを中心に捉えれば自然な選択 アプリのビジネスロジックは JavaScript 書く ERP のような複雑なロジックでは比重が大きくなる HCL / CUE と JavaScript の混在 HCL 内の インライン JS 、外部 JS ファイルのパスの参照 言語間の参照に型が付かず、補完も効きにくい アプリ全体を見渡しにくい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 5

Slide 6

Slide 6 text

SDK 既存の仕組みでつらくなってきたところを踏まえつつTypeScriptで「いい感じ」に書けるように する 型をいい感じに提供したい 正確な型を / 軽快に ユーザーコードをいい感じに書かせたい ローカルマシン・Platform を意識しない / 余計なコードを含まずにバンドル AI にいい感じでコードを書かせたい AI の利用行動を観測して SDK を直す TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 6

Slide 7

Slide 7 text

型をいい感じに提供したい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 7

Slide 8

Slide 8 text

型をいい感じに提供したい いい感じとは? 正確な型を 型を適切に狭めて補完を効かせる 型チェックで早期にエラーを発見できる 軽快に 軽い IDE 補完と型チェックを重くしない 快適 コマンド実行などの手間がない 難しいことを意識しなくていい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 8

Slide 9

Slide 9 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 提供したい体験 // tailor.config.ts import { defineConfig } from "@tailor-platform/sdk"; export default defineConfig({ env: { API_BASE_URL: process.env.API_BASE_URL, LOG_LEVEL: process.env.LOG_LEVEL ?? "warn", }, // ... }); // resolvers/checkout.ts createResolver({ body: ({ env }) => fetch(env.API_BASE_URL), // ← 補完 & タイポでエラー }); defineConfig に書いた env キーが、別ファイルで型として効く TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 9

Slide 10

Slide 10 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 課題 env キーが決まるのは ユーザーが config を書いた時点 SDK の型定義は publish 時点で固定 → SDK 配布後に、ユーザー側から型情報を「差し込める」経路が必要 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 10

Slide 11

Slide 11 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 取り組み ①: コマンドで 環境変数の型宣言を生成 tailor-sdk generate でユーザーの config ファイルを読んで型定義を含むファイルを生成 declare module "@tailor-platform/sdk" { interface Env { API_BASE_URL: string; LOG_LEVEL: string; } } TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 11

Slide 12

Slide 12 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 取り組み ②: 生成した型を SDK の内部で使う // SDK 内部(npm install 時点で凍結) export interface Env {} export type TailorEnv = keyof Env extends never ? Record // 未生成なら fallback : Env; // 生成後はユーザーのキー・値の型 export const createResolver = (opts: { body: (args: { env: TailorEnv }) => Result }) => { /* ... */ }; createResolver の body は TailorEnv を介して Env を受け取る 未生成でも TailorEnv は壊れない(fallback で広い型に倒す) TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 12

Slide 13

Slide 13 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 取り組み ③:利用側で具体型として効く // TailorEnv が { API_BASE_URL: string; LOG_LEVEL: string } に置き換わる createResolver({ body: ({ env }) => { fetch(env.API_BASE_URL); // ← 補完が効く env.UNKNOWN_KEY; // ← Property 'UNKNOWN_KEY' does not exist }, }); TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 13

Slide 14

Slide 14 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 類似事例:wrangler types // worker-configuration.d.ts — wrangler.jsonc から生成 interface __BaseEnv_Env { MY_KV: KVNamespace; API_BASE_URL: "https://api.example.com"; } declare namespace Cloudflare { interface Env extends __BaseEnv_Env {} } interface Env extends __BaseEnv_Env {} // 利用側(fetch handler) export default { async fetch(req: Request, env: Env) { return env.MY_KV.get("..."); // ← 補完が効く }, }; TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 14

Slide 15

Slide 15 text

型をいい感じに提供したい: 型を正確に:ユーザー定義の型を提供 類似事例:TanStack Router のファイルベースルーティング // routeTree.gen.ts — Vite plugin / tsr generate が生成 declare module "@tanstack/react-router" { interface FileRoutesByPath { "/posts/$postId": { ... }; } } // 利用側 import { Link } from "@tanstack/react-router"; // FileRoutesByPath から path が補完 ; TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 15

Slide 16

Slide 16 text

型をいい感じに提供したい: 型を軽快に 提供したい体験 正確な型を提供するのは前提 軽い 補完・型チェックがすぐ反応する 快適 コマンド実行などの手間がない 難しいことを意識しなくてよい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 16

Slide 17

Slide 17 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 課題 推論と生成のトレードオフ: 推論(動的に解決) 利点:書き換えがその場で反映される 欠点:複雑な型では、編集のたびに重い型計算が走る 生成(静的に固定) 利点:事前計算済みで参照側は軽い 欠点:コマンドなどで再生成が必要 → 特性に応じて使い分ける TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 17

Slide 18

Slide 18 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 取り組み:基本は推論、必要なものだけ生成に移す 基本:推論 書き換えがその場で反映される 生成に移すケース スキーマ由来の構造型(DB など) 滅多に変わらない・推論が重い config で宣言する識別子( 「型を正確に」で扱った env キーなど) 利用側で declaration merging などを意識させない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 18

Slide 19

Slide 19 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 例:SDK 内部の Zod schema 入出力型を事前計算 SDK 内部のスキーマは、ユーザーから見れば package install でしか更新されない(= 更新頻度が最も低い領域) 。 // parser/**/schema.ts — Zod schema を SSoT とする export const UserSchema = z.object({ id: z.string(), name: z.string() }); // SDK build 時に生成(z.infer なし) export type User = { id: string; name: string }; z.transform などの型を zod-to-tsでは生成できなかったため自作 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 19

Slide 20

Slide 20 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 例:SDK 内部の Zod schema 入出力型を事前計算 利用側は計算済みの型を import するだけ。 // ユーザー側 import type { User } from "@tailor-platform/sdk"; const u: User = { id: "1", name: "A" }; // ← z.infer の展開なし z.infer の型計算コストを利用側に持ち込まない fixture ごとに型 instantiation 数を 1/4 〜 1/10 まで削減 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 20

Slide 21

Slide 21 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 例:ユーザーの DB スキーマから kysely 型を生成 kysely-type plugin で kysely 用の Database 型を生成 + PF上でのDB接続情報のラップ DB 定義は散らばる可能性があり、1 つずつ import するより生成で集約してしまったほ うが楽 推論コストを抑えつつ、定義の所在も意識せずに済む 利用側は集約済みの 1 つの型を import するだけ kysely 呼び出しで行型まで推論される TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 21

Slide 22

Slide 22 text

型をいい感じに提供したい: 型を軽快に:推論と生成のトレードオフ 類似事例:Prisma スキーマファイル( schema.prisma )から prisma generate で TypeScript 型を出力 利用側は計算済みの型を import するだけ 推論の型計算コストが乗らない 参考: Why Prisma ORM Checks Types Faster Than Drizzle TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 22

Slide 23

Slide 23 text

型をいい感じに提供したい まとめ 小項目 提供したい体験 取り組み 型を正確に:ユーザー定義 の型を提供 ユーザーが定義した型が SDK の型として効く 空 interface を declare module で埋める (declaration merging) 型を軽快に:推論と生成の トレードオフ 補完が軽い、難しいことを意 識しなくてよい 領域ごとに推論と生成を使い分ける ユーザーが書く設定の型は、ユーザー固有の値に従わせる。 生成 / 推論を一律にせず、境界の置 き方を選ぶ。 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 23

Slide 24

Slide 24 text

ユーザーコードを いい感じに書かせたい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 24

Slide 25

Slide 25 text

ユーザーコードをいい感じに書かせたい いい感じとは? ローカルマシン・Platform を意識しなくていい 同じコードがローカルマシン(Vitest)と Platform(以下 PF) で同じように動く 余計なコードをバンドルしない PF に反映されるコードは必要最低限にする TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 25

Slide 26

Slide 26 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 提供したい体験 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 26

Slide 27

Slide 27 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 提供したい体験 import { child } from "./child-job"; export const parent = createWorkflowJob({ name: "parent", body: async ({ userId }) => { return await child.trigger({ userId }); }, }); 普通のコードが書ける 子ジョブを .trigger() で呼ぶだけ ローカルマシンと PF の両方でこれが動作するようにする ローカルマシンでテストできる ローカルマシンでテストした通りに PF で実行される TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 27

Slide 28

Slide 28 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい ローカルマシンと PF での実行環境の差 観点 ローカルマシン PF 実行ランタイム Node.js Web Standards のみ 実行単位 1 プロセスで全部走る ジョブごとに切り離された環境 ジョブ間呼び出し 普通の関数呼び出し PF が仲介 globalThis.tailor.* undefined ランタイムが提供 → この差を SDK で埋める TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 28

Slide 29

Slide 29 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 取り組み ①:Platform が注入するグローバルオブジェクトをラップする // SDK が publish する .d.ts const child = createWorkflowJob({ name: "child", body: async ({ userId }) => { console.log("hello"); return true; }, }); child.trigger(args); // => tailor.workflow.triggerJobFunction("child", args) 提供された関数には型がついてるので、 globalThis.tailor.* を気にせずに書ける TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 29

Slide 30

Slide 30 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 取り組み ②:ローカルマシン用に Vitest の Test Environment を提供 テスト実行時の環境を差し替えるための Vitest の仕組み // vitest.config.ts import { tailorRuntime } from "@tailor-platform/sdk/vitest"; export default defineConfig({ test: { environment: "tailor-runtime" }, plugins: [tailorRuntime()], }); tailor-runtime 環境がやること: globalThis.tailor.* を mock として自動注入 import "node:fs" 等を書き換え、エラーで代替を提示 ジョブ間の呼び出しの仲介 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 30

Slide 31

Slide 31 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 埋められないギャップ tailor-runtime 環境は beta 把握済みの差は塞ぎ中 塞ぎきれない例:PF にはない globalThis のプロパティが残る Vitest がテストランナー動作のために必要とするものは除外できない 結果として process 関連 / require / module / exports などが、PF にはないのにロ ーカルマシンでは生きてしまう TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 31

Slide 32

Slide 32 text

ユーザーコードをいい感じに書かせたい: ローカルマシン・PF を意識しなくていい 類似事例:@cloudflare/vitest-pool-workers ローカルマシン pool が Miniflare 経由で workerd を別プロセスで起動 bindings は Miniflare のローカル実装 PF workerdで実行 利点:runtime と Web Standards API は PF と同じ workerd 欠点:プロセス境界越しに参照を共有できない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 32

Slide 33

Slide 33 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 提供したい体験 // parent-job.ts import { child } from "./child-job"; export const parent = createWorkflowJob({ name: "parent", // PF のバンドルに乗ってほしいのは body の中身だけ body: async ({ userId }) => { return await child.trigger({ userId }); }, }); PF のバンドルには parent ジョブの実装に必要なものだけ乗ってほしい import してある child の実装は parent 側のバンドルに含まれないでほしい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 33

Slide 34

Slide 34 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 提供したい体験 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 34

Slide 35

Slide 35 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 課題 各ジョブを個別にバンドルして deploy したい 無秩序に書かれると、各バンドルに余計なコードが混ざりやすい parent が child を使用していると、単純なバンドルでは child の実装まで parent 側に取り込まれる SDK 自体のコードもバンドル結果に含まれる PF での実行時には必要ないものがほとんど TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 35

Slide 36

Slide 36 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 取り組み ①:config の glob + export でバンドルの境界を作る // tailor.config.ts export default defineConfig({ db: { main: { files: ["src/types/**/*.ts"] } }, resolver: { main: { files: ["src/resolvers/**/*.ts"] } }, executor: { files: ["src/executors/**/*.ts"] }, workflow: { files: ["src/workflows/**/*.ts"], job_files: ["src/jobs/**/*.ts"], }, }); glob にマッチしたファイル内で export されたものだけがバンドル対象 最低限の境界が作れる TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 36

Slide 37

Slide 37 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 取り組み ②:SDKのコードをレイヤーごとに分離 packages/sdk/src/ ├── configure/ ユーザーが直接 import する API ├── parser/ Zod による検証・正規化(CLI から呼ばれる) └── cli/, plugin/, vitest/ CLI コマンド / プラグイン / テスト環境 sub-path export で公開エントリを切る default は configure/ のみ、 parser / cli / plugin は別エントリ 重い runtime は parser 以降の層側に隔離されてユーザーバンドルには流れ込まない Lint で configure から parser / cli / plugin への import を遮断 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 37

Slide 38

Slide 38 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 取り組み ②: configure はほぼ identity な関数群 configure の define* / create* は型を効かせるためのゲートで、中身はほぼ空: // configure/config.ts(実物) /* @__NO_SIDE_EFFECTS__ */ export function defineConfig(config: Config) { return config; } 型推論を効かせる役割だけを configure に置く configure 層がユーザーバンドルに載ることは許容 @__NO_SIDE_EFFECTS__ などを付与しつつバンドラに任せる TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 38

Slide 39

Slide 39 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 取り組み ③:AST 操作で各 job を chunk 単位に切り出す // ユーザーが書くコード(ローカルマシンではこのまま動く) import { child } from "./child"; export const parent = createWorkflowJob({ name: "parent", body: ({ userId }) => child.trigger({ userId }), }); // parent.chunk — AST 書き換え後 export const parent = createWorkflowJob({ name: "parent", body: ({ userId }) => tailor.workflow.triggerJobFunction("child", { userId }), }); TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 39

Slide 40

Slide 40 text

ユーザーコードをいい感じに書かせたい: 余計なコードをバンドルしない 類似事例:Remix のルートモジュール // app/routes/posts.$id.tsx export async function loader({ params }: LoaderFunctionArgs) { /* server */ } export async function action({ request }: ActionFunctionArgs) { /* server */ } export default function Post() { /* client */ } フレームワーク規定の書き方で、同じファイル内に server / client を共存させる export で境界を引く loader / action → server バンドル default export → client バンドル TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 40

Slide 41

Slide 41 text

ユーザーコードをいい感じに書かせたい まとめ 小項目 提供したい体験 取り組み ローカルマシン・ PF を意識しなくて いい 同じコードがローカルマシン (Vitest)と PF で同じように動 く globalThis.tailor.* の型を SDK で宣言、ローカル マシンは Vitest custom environment で揃える 余計なコードをバ ンドルしない PF 側のバンドルには必要なも のだけが乗る config の glob で範囲を限定 + SDK 内部の layer 分離 + AST で chunk 単位に分解 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 41

Slide 42

Slide 42 text

AI にいい感じで コードを書かせたい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 42

Slide 43

Slide 43 text

AI にいい感じでコードを書かせたい いい感じとは? 正しく書ける ユーザーが指定した仕様通りに書ける SDK が想定する API の使い方から外れない 実行コストが小さい 実装時間が短い トークン消費が膨らまない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 43

Slide 44

Slide 44 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 提供したい体験 実装時間・トークン消費が膨らまない Read が早く終わってすぐに書き始められる 試行錯誤で書き直しが起きない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 44

Slide 45

Slide 45 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 課題 AI が「どこを読みにいって」 「どう試行錯誤して」が見えない 直感で「ここを直せば AI が書きやすくなる」と言えても、効いたか分からない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 45

Slide 46

Slide 46 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 取り組み ①:llm-challenge — AI 向け SDK のベンチマーク 小さく切り出した問題を AI に解かせ、結果を指標として残す problem.md にはヒントを書かない LLM がパッケージから自力で API を発見できるかを試す --sdk-branch + --iterations で任意の git ref を pack して A/B 観測指標:初回試行成功率 / 実行時間 / 最終正答率 TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 46

Slide 47

Slide 47 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 取り組み ① の実例:JSDoc で初回試行の精度向上 主要な API に JSDoc を追加 指標 JSDoc なし JSDoc あり 初回試行で詰まる問題 1 / 12 問 0 / 12 問 全問合計の実行時間 10m 34s 2m 31s (-76%) 最終正答率 100% 100% 詰まる 1 問が初手で通るだけでなく、他の問題でも API を調べる時間が減って実行時間が縮 んだ 最終正答率は変わらないが、辿り着きやすさは時間に出る TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 47

Slide 48

Slide 48 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 取り組み ②:LLM のログから誤推論を拾って API 形に戻す 問題を 1 つ LLM に解かせ、書きかけて捨てた候補を確認すると: LLM が書きがち 正しい書き方 db.string().optional() db.string({ optional: true }) db.string({ unique: true }) db.string().unique() db.string().default(5) db.string().hooks({ create: ({ value }) => value ?? 5 }) 最終的には正しく書けるが、途中で似ている他のライブラリのAPIに引っ張られている? TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 48

Slide 49

Slide 49 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 取り組み ② の実例:オブジェクトリテラル形式の検証 Rewrite your CLI for AI agents に着想を得て、メソッドチェーンと並行で追加 // fluent: db.string().unique().optional() // object literal: { kind: "string", unique: true, optional: true } ベンチマーク結果、object literal は確認 Read が増えて遅くなった kind: "string" の有効値や kind 別 option を毎回 grep しているっぽい TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 49

Slide 50

Slide 50 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 取り組み ③:実プロジェクトから学習する ベンチマーク(取り組み ①)にも単発の試行錯誤(取り組み ②)にも出ない、実際の開発現場 から学ぶ SI 案件で LLM が書いたコードのログから書き間違いを抽出する skill を社内配布 配布したばかりで SDK 改善に戻した実例はまだない TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 50

Slide 51

Slide 51 text

AI にいい感じでコードを書かせたい: AI の使い心地を SDK の指標にする 類似事例:Angular Web Codegen Scorer フレームワーク横断のコード生成ベンチマーク Angular MCP Server LLM が Angular を「呼べる」第一級の窓口 AngularはAI志向のフレームワークへ AI でゼロから書ける / 既存コードを置き換えられるフレームワークを目指す TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 51

Slide 52

Slide 52 text

AI にいい感じでコードを書かせたい まとめ 信号源 拾えるもの 自前のベンチマーク AI に同じ課題を繰り返し解かせる 初回成功率・実行時間・最終正答率 LLM の試行ログ 1 タスク中に AI が書いて捨てた候補を見る 数字に出ない誤推論(似た別 API への引きずられなど) 実プロジェクトのログ 社内 SI 案件で AI が書いたコードを見る ベンチや単発試行では出ない、現場でしか起きないパターン TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 52

Slide 53

Slide 53 text

TypeScript で Platform SDK を作る技術 全体のまとめ 章 / 主題 鍵 型をいい感じに提供したい ユーザー固有の型を SDK に取り込 む / 領域ごとに推論と生成を使い分 ける 空 interface に declaration merging で型を埋める/重い領域は CLI で生 成、軽い領域は推論で受ける ユーザーコードをいい感じに書かせ たい ローカルマシン・PF の差を消す / PF には必要なものだけを送る globalThis.tailor.* を SDK で型宣言+Vitest custom environment で mock を注入/config の glob+層分離+AST で chunk 分割 AI にいい感じでコードを書かせたい AI の使い心地を観測指標にして SDK を直す 自前のベンチマーク・LLM の試行ログ・実プロジェクトのログを組み合 わせる TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 53

Slide 54

Slide 54 text

We're hiring Tailor Platform™ を一緒に作るエンジニア募集 募集職種 FDE — Forward Deployed Engineer Platform — Tailor Platform™ SDK / AppShell / Core Platform / SRE AI — AI プロダクト / AI プラットフォーム こんな人と話したい 人間と AI(Coding Agent / LLM)の協調を前提に開発・設計できる 個別の実装より、再利用可能な仕組み・抽象化を考えるのが好き 不確実性の高い状況でも試行錯誤しながら前進できる コンタクト:テイラー株式会社のブース / Tailor Careers TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript 54

Slide 55

Slide 55 text

Thanks TSKaigi 2026 TypeScript で Platform SDK を作る技術 / Building a Platform SDK in TypeScript