
TypeScript
イベント
該当するコンテンツが見つかりませんでした
マガジン
技術ブログ
SKYMENU MobileのAIセーフカメラでも活用されている、Azure Durable Functionsの基本概念や主要な関数、代表的な利用パターンを解説します。また、状態管理の仕組みやエラー処理とリトライ機構についても実践的なTypeScriptのコード例を交えて紹介します。
※ この記事は、筆者が AI エージェント(Claude Code)と対話しながら執筆しました。読了 ...
こんにちは、新卒3年目でビジネスイノベーション統括本部ITD1-3の堀川です。 愛用しているキーボードは GoForty v2のOrtho配列 です。 今回、私が普段の業務で使用しているTypeScriptをテーマにした大型カンファレンス『TSKaigi 2026』の参加レポートを書かせていただきました! 去年の参加レポート記事に引き続き、カンファレンスの様子や感想、魅力などを発信していきます TSKaigi2025で分かったTypeScriptの流行 ↑今年の愉快なTSKaigi参加メンバーたち カンファレンス概要 情報区分 カンファレンス詳細 イベント名 TSKaigi 2026 開催日 2026/05/22、2026/05/23 開催場所 ベルサール羽田 京急空港線羽田空港第3ターミナル駅から徒歩5分 ミッション 学び、繋がり、"型"を破ろう セッション感想 ここでは私が参加したセッションの中で、特に面白かったものを自分なりの理解を交えて紹介します セッション感想① 実践TanStack Start: 新規プロダクトを開発して確立した、サーバーとクライアント境界の設計パターン セッション概要 https://2026.tskaigi.org/talks/26 スピーカー Shimmy スライド資料 https://speakerdeck.com/kaminashi/practical-tanstack-start-server-client-boundary-patterns?slide=3 Next.js と同じ React 向けフルスタックフレームワークである TanStack Start に関するセッションです。まだ v1.0 未満でコミュニティや事例が少ない中、 実際に採用した新規プロダクトの設計知見 を聞ける貴重な内容でした。 loader と Server Functions の責務設計 TanStack Start を使う上で核心となるのが、この2つの責務をどう分けるかという問題です。 役割 loader ページ描画「前」に走る処理を書く場所 Server Functions クライアントから呼び出せるサーバー側の処理 Next.js ではこの2つの挙動がフレームワーク側であらかじめ決まっています。一方 TanStack Start は、どちらに何を書くかを 開発者自身が決める 設計です。 この違いは開発体験にも現れます。Next.js はキャッシュ挙動がフレームワーク内部で自動的に決まるため、「なぜデータが古いまま表示されるのか」を調べるために内部実装を読み込むことも少なくありません。TanStack Start はすべての挙動を自分たちのコードに明示する設計のため、 動作への理解を保ったまま開発できる というメリットがあります。 設計パターン:loader 編 loader 内の取得は最小限に留め、各コンポーネントが必要なデータを自分で取得する というアプローチです。 // loader では認証情報から tenantId だけを取り出すexport const Route = createFileRoute("/_authed/orders")({ loader: ({ context: { session } }) => ({ tenantId: session.tenantId }), component: OrdersPage,});// 各コンポーネントが useQuery で必要なデータを取得するfunction OrdersPage() { const { tenantId } = Route.useLoaderData(); const { data } = useSuspenseQuery(ordersQueryOptions(tenantId)); return ( <> <NotificationBadge /> {/* 子の中で useQuery */} <OrdersTable orders={data} /> <Recommendations /> {/* 子の中で useQuery */} </> );} // loader では認証情報から tenantId だけを取り出す export const Route = createFileRoute ( " /_authed/orders " )( { loader : ({ context : { session } }) => ( { tenantId : session . tenantId } ) , component : OrdersPage , } ) ; // 各コンポーネントが useQuery で必要なデータを取得する function OrdersPage () { const { tenantId } = Route . useLoaderData () ; const { data } = useSuspenseQuery ( ordersQueryOptions ( tenantId )) ; return ( <> < NotificationBadge /> { /* 子の中で useQuery */ } < OrdersTable orders ={ data } /> < Recommendations /> { /* 子の中で useQuery */ } </> ) ; } 設計パターン:Server Functions 編 ① 横断関心事は Middleware へ切り出す ログ出力や認証チェックなど、複数の Server Functions に共通する処理は handler に直接書かず、Middleware として分離します。 export const loggerMiddleware = createMiddleware({ type: "function" }).server( async ({ next, functionId }) => { const requestId = crypto.randomUUID(); logger.info({ requestId, functionId }, "handler:start"); return next({ context: { requestId } }); },); export const loggerMiddleware = createMiddleware ( { type : " function " } ) . server ( async ({ next , functionId }) => { const requestId = crypto . randomUUID () ; logger . info ( { requestId , functionId }, " handler:start " ) ; return next ( { context : { requestId } } ) ; }, ) ; ② handler にはロジックや I/O の詳細を直接書かない handler は「受け取って委譲する」だけにとどめ、実装の詳細は別の関数に任せます。 export const saveOrder = createServerFn({ method: "POST" }) .middleware([loggerMiddleware]) // 横断関心事 .inputValidator(saveOrderInputSchema) // 入力の検証 .handler(async ({ data }) => upsertOrder(data), // ロジックは別関数へ委譲 export const saveOrder = createServerFn ( { method : " POST " } ) . middleware ([loggerMiddleware]) // 横断関心事 . inputValidator (saveOrderInputSchema) // 入力の検証 . handler ( async ({ data }) => upsertOrder (data) , // ロジックは別関数へ委譲 この設計により責務が自然と分離され、人間にも AI にも読みやすいコードベースが実現できます。 まとめ もし TanStack Start を新規プロダクトへ導入するとしたら、Next.js との最大の違いは「フレームワークに動作を任せるか、自分たちで明示するか」という設計思想の差です。 使い分けの目安としては、SEOや高速な初期表示が求められるサービス、またはチームに Next.js の知見が豊富な場合は Next.js が無難です。一方、複雑なサーバー/クライアント間のデータフローを自分たちで制御したい場合や、コードベースの挙動を隅々まで把握したい場合は TanStack Start が向いているといえます。 Next.js に慣れ親しんでいるほど、最初は自由度の高さに戸惑うかもしれません。しかし今回紹介した設計パターンを最初から取り入れることで、コードベースの見通しを保ったまま開発をスタートできます。 「なぜこの挙動になるのか」を把握したまま開発したい新規プロダクトにおいて、TanStack Start は有力な選択肢になりそうです。 セッション感想② AI時代に考える、Branded Types で実現する堅牢な型付け セッション概要 https://2026.tskaigi.org/talks/62 スピーカー 池奥裕太 / @yuta-ike スライド資料 https://www.docswell.com/s/4136989/Z6NJ78-tskaigi2026#p1 TypeScript の中でもさらに厳格な型定義を行う Branded Types について、その意義と具体的な魅力をわかりやすく解説したセッションでした。 型チェックの意義 まず前提として、型チェックには4つのパターンがあります。 実装 型チェック 評価 正しい 通る 嬉しい 間違っている 通らない 正常 正しい 通らない よくある・辛い 間違っている 通る 一番避けたい 「実装が間違っているのに型チェックが通る」とは、たとえば次のようなケースです。 <em>// 足し算関数 (number + number → number)</em>function add(a: number, b: number): number { return 0; // 常に 0 を返す} < em > // 足し算関数 (number + number → number)</em> function add ( a : number , b : number ): number { return 0 ; // 常に 0 を返す } 足し算を期待しているのに常に 0 が返ってくる実装ですが、戻り値の型は number として正しいため、型チェックでは検知できません。 これは極端な例ですが、AI に実装を依頼した際に「パッと見は問題なさそうだが、よく読むと意図した処理になっていない」という経験をした方もいるのではないでしょうか。こうした問題に対処するために、より厳格な型定義が求められます。そこで有効なのが Branded Types です。 Branded Types とは 同じ構造を持ちながら意味合いの異なる型(例: User と Book )を区別するために、架空のプロパティ __type を付与して型を識別する手法です。 User 型を期待する引数に Book 型を渡そうとすると、型チェックでエラーになります。 function createUser(user: User) { ... }const book: Book = { id: getUUID(), name: "吾輩はエンジニアである", date: new Date(2000, 0, 1),} as Book;createUser(book); // TypeError: Book 型を User 型に代入できない function createUser ( user : User ) { ... } const book : Book = { id : getUUID () , name : " 吾輩はエンジニアである " , date : new Date ( 2000 , 0 , 1 ) , } as Book ; createUser (book) ; // TypeError: Book 型を User 型に代入できない プロダクト開発における Branded Types の使いどころ セッションでは、Branded Types を効果的に活用するための方針として2つが紹介されていました。 ① ドメインモデルを区別する 変数名で区別できれば理想的ですが、AI が FailedUploadingFileId のような丁寧な命名を常にしてくれるとは限りません。せいぜい FailedFileId 程度になることも多いでしょう。Branded Types と型チェックを組み合わせることで、その区別をコードレベルで担保できます。 ② 値の状態や属性を表現する たとえばバックエンドへ送る string 型の値に対して、「型チェック済み」「ドメインチェック(記号を含まないなど)済み」という条件を本当に満たしているかどうかは、通常の型定義だけでは保証できません。Branded Types を使うことで、こうした「チェック済みの状態」を型として表現できます。 Branded Types によって型安全なコードを書くことで、コードの前後を読まなければ判断できなかった要素を、型定義を見るだけで把握できるようになります。 まとめ AI コーディングが普及した今、コードを書く速さよりも「AI が生成したコードを正しく検証できるか」が重要になっています。Branded Types が注目されている背景には、まさにこの変化があると考えています。 型定義を厳格にしておくことで、AI が生成したコードが意図通りかどうかを、コードを細かく読まなくても型チェックの段階で検知できるようになります。「関数の引数・戻り値の型を厳格に定義する」「副作用を持たせない」といった方針がレビューコスト削減につながる事例として挙がっている中で、Branded Types はこうした流れと特に相性の良いアプローチです。 「AI に実装を任せる機会が増えた」と感じている方ほど、導入を検討する価値があるといえるでしょう。 企業ブース 今年も1日目にかなりの数を回らせていただきました! 去年とは違い、スタンプラリーは企業名別に区切られておらず、どのブースに行っているかの進捗を忘れてしまうことがしばしばありました... (今年はラムネがとても多かったです。嬉しい) セッション感想に力を入れ過ぎて、文字数がかなり多くなってしまったので、今回は1社さんだけの紹介になります... テイラー株式会社 テイラー株式会社は、TSKaigiに参加されている企業の中で特に印象に残った会社です。TypeScriptの特徴的な事業活用事例を持つ会社で、その内容がとても興味深かったのでご紹介します。 具体的には、エンタープライズ向けの大規模なERPを10倍の速さで構築できる、世界初のヘッドレスERPプラットフォームを事業として提供しています。 会社ページ ERP(Enterprise Resource Planning)とは、企業の基幹業務(会計・在庫・人事・販売など)を一元管理するシステムのことで、MicrosoftやFreeeなどのサービスが有名です。 しかも、このプラットフォームは会社独自のReactアプリケーションフレームワークで開発されており、その保守運用はもちろん、専門エンジニアとして開発サポートも担っているとのことでした。 独自フレームワーク(app-shell)のリポジトリ 会社の事業として独自のフレームワークを開発するだけでなく、その開発サポート、つまりテックリード的なことも担っているというのは、エンジニアとして琴線に触れるものがありました。 TSKaigiに参加して 去年よりもAIの活用をからめたセッションもありましたが、それ以上に型定義を厳格にするBranded Typesや最近出てきたTanstack Startに関する内容が複数あったのが驚きでした。 特にBranded Typesに関してはAIに実装を任せることが多くなったからこそ、型チェックを通した品質の担保に注目されているのかな、と感じています。 去年に引き続き、セッションや企業ブースでTypeScriptやフロントエンドの流行を学ぶことができ、とても貴重な経験になりました! 業務はもちろんプライベートでの開発モチベにも繋がったので、これからも開発に励んでいきたい所存です。 おまけ 去年に引き続き、サプライ品がとても良かったので、社員証に付けさせていただいてます! 今年は先端がカラビナ(?)になっており、付けやすくなっていました。ありがとうございます。 また、1日目のオープニングが終わった直後、見覚えのあるキーボードを見かけてお声かけした際、Xで一方的に存じ上げてた某モテるWeztermの人とお話しすることができました! モテるターミナルにカスタマイズしよう(WezTerm) 特徴的なキーボードは名刺になります() ←Weztermの方のキーボード 私のキーボード→



















