「TSKaigi2024」に参加してきました

  • 2024/5/11
  • https://tskaigi.org/
  • オフライン参加だけで200人以上?いる大きなイベントで遠方からの参加者も多かったようです
  • js/ts系だとReact/Nextに偏りがちなイメージでしたがサーバーサイドの話を多く興味深い話を多く聞けました
  • 有料のイベントだからか昼食のお弁当がおいしかった

Keynote: What's New in TypeScript

  • Daniel Rosenwasserさん

TS 5.4/5.5

  • NoInfer
    • NoInfer<T> とするとTにないプロパティ入ってるとエラーに出来る
  • JSDoc
    • JSでコメントでtypeをimportするとその型でチェックできる
  • 正規表現の型チェック
    • 不正な正規表現を型エラーにできるようになった
  • filterしたあとの型
    • filterでundefined取り除いても型でundefinedが残っちゃうようなやつが解消される

Prisma ORMを2年運用して培ったノウハウを共有する

Prisma ORM

  • RDBに加えてドキュメント指向DBも対応
  • 強力な型定義
  • classじゃなくてobjectを返す

ノウハウ

パフォーマンス

  • includeでリレーション先も取れる
    • デフォルトではjoinされるわけではなく複数SQL叩かれる
    • ものによっては通信のオーバーヘッドがかかる
    • DBのオプティマイザの恩恵を受けられない
  • そういう時はqueryRawで直接SQL書いてる
  • updateManyやdeleteManyを原則使う
  • バージョンがあがって改善もされてきてる

スケーラビリティ

  • readが多いからスケールしたい
    • Read Replica
    • read専用のノードを作る
    • クエリの投げ先を切り替える
    • PrismaClientをラップするclientを作って対応
    • 公式でextension-read-replicaというのもある

セキュリティ

  • whereにundefinedを渡すと条件なしになっちゃう
  • RowLevelSecurity(PostgreSQLの機能)
  • zodのparseで型に未定義に項目を切り落とす

テスタビリティ

  • seedの準備が大変
  • 実行後のDBのチェックが大変
  • クリーンアップが大変
  • →内製でテストランナーを作ってOSS化した

オブザーバビリティ

  • Prismaが内部でどんなことをやってるか可視化したい
  • PrismaでOpenTelemetryを使う
    • OpenTelemetry tracingというのがある
  • Datadogで可視化

TypeScript 関数型バックエンド開発のリアル

関数型でのドメインモデル

  • Domain Modeling Made Functional
    • ドメインオブジェクトを型で表現
    • エラーによる分岐はResult型でエラー処理を明示する
  • オブジェクトの変更は「関数適用による状態遷移」としてイミュータブルに
  • Result型はneverthrow
  • 命令的に書かずに関数的に書く
    • 状態を変化させた戻り値を受け取る
    • 引数と戻り値の型を明示できる
  • Resultを返す関数を合成して一本道の処理フローを作る
  • IO -> ドメインオブジェクトの状態遷移 -> IO

TypeScript の抽象構文木を用いた、数百を超える API の大規模リファクタリング戦略

ExpressからNestJSへの移行

  • 400APIの大規模な移行
    • 段階的な移行だとせっかくの新しい機能が使えないものが残っていや
    • 正規表現でやってもいいが書く方が統一されているわけではなく現実的に難しい
    • →ASTレベルで操作して移行するとよさそう
  • AIで変換するのは再現性が低くてレビューコストも高い
  • ts-morphで解析して置換する

Type-safety in Angular

Angular

  • Component/Bootstrapping
  • 最近はSignalが普通に使えるようになった

Angularの型チェック

  • templateの中でもTSのエディタ支援がちゃんと受けられる
  • コンポーネントに渡す引数も型チェックしてくれる
    • 定義されてないもの渡したり
    • 必須の項目を渡してなかったり

Angularの型チェックの仕組み

  • Template Type-Checking Engine
    • Type Check Blockを通してチェックされる
    • コンポーネントのコードから意味的に正しい純粋なTSのコードを生成してエラーにならないかチェックしてる
    • LanguageServiceでリアルタイムで

サービス開発におけるVue3とTypeScriptの親和性について

Vue

  • Vue2が2023末でEOLになった
  • Vueとtsの親和性
    • 型付け(Type Inference)と論理構成(Logic Composition)
  • コンポーネントを作って組み合わせる
    • 親から子へはpropを渡してデータを渡す
    • 子から親へはEventEmittingで渡す

Vueのts対応

  • Vue2の頃
    • ロジックのみを外部ファイルに分けづらい
    • 状態管理ツールから型がわたってこない
    • thisやテンプレートに型が反映されない
  • CompositionAPI
    • コンポーネントを構成する関数ベースのAPIセット
      • ロジックを切り出すことが出来るようになった
      • 型付けも改善
  • コンポーネントランタイムの型
    • defineComponent
    • Emitsも型付け可能に
  • Volar.jsとlanguage-tools
    • エディタのツールに適用するためのもの

状態管理と型

  • Composables
    • ReactHooksみたいな感じで処理をかけるのでロジックを外に切り出せる
    • SSR時はそのままでは動かない
  • Pinia
    • ReactのContextAPIみたいな感じ?

TypeScriptとGraphQLで実現する型安全なAPI実装

APIの型付け

  • fetchしたresponseの型付けは祈りでしかない
    • そうならないために片付けしたい
  • 外部I/Oに対する片付けが不十分だと静的型付けの恩恵を活かせない
  • 型をつける技術
    • OpenAPI
    • gRPC
    • GraphQL

GraphQL

  • GraphQLのスキーマからtsの型を生成できる
    • それを元にクライアント/サーバのコードを書く
    • GraphQL Codegen
  • クライアントサイド
    • GraphQL Codegen Client Preset
    • クエリから生成した型を使う
      • スキーマ設計生成した型ではダメ
      • 必要なフィールドだけ指定するとエラーで落ちるので
      • クエリ文字列からcodegenで型を生成してくれる
    • Fragment Colocation
      • すべての子孫コンポーネントで使われるpropsを知ってないといけないのを解決
      • コンポーネントは自分のコンポーネントで必要なフラグメントの型だけ定義
      • 自分の子供と自分が必要なものをマージする
      • そうすればどこからも使われないと大元からも消える
      • codegenはこれにも対応している
    • Fragment Masking
      • 自分のコンポーネントで定義してない項目を使うと型エラーにしてくれる
      • useFragment関数を通すことで実現してる
  • サーバサイド
    • GraphQL Codegen Typescriot Resolvers
      • server-presetというのもあるが癖が強め
      • 以下に対応
        • graphql-js
        • Apollo Server
        • GraphQL Yoga
      • NextJSはちょっと特殊
    • スキーマから生成した型を使えばOK
    • すべてのフィールドを指定されなか時
      • 指定されなかったフィールドを取得しに行く処理が無駄になる
      • フィールドごとにresolverを分けることができる
      • そのままだと型エラーになる
      • Resolverが扱う型をmappersでmodelで定義したものにすると指定できる

Prettierの未来を考える

Prettier

  • コードフォーマッター
    • 設定が少ない
    • web周りの多くの言語をサポート
  • フォーマットに関する本質的でない議論をしなくてよくなる
  • 2017年頃に公開

Prettierの課題

  • 使い勝手の悪さ
    • lintの機能には関与しない
    • それを検知するにはESLintなどが必要
    • ESLintとフォーマットのルールが衝突しないようにしないといけない
      • ライブラリ入れて設定書かないといけない
      • そのルールも定期的に変わる
    • TypeScriptと組み合わせるにはそれもライブラリが必要
  • 実行時間の遅さ
    • format on saveで実行
      • このパターンならあんまり問題にならない
    • CIやローカルでプロジェクト全体に適用
      • これは遅くなる

課題を解決してるライブラリ

  • Deno
    • JSのランタイム
    • デフォルトでts対応
    • deno lint とか deno format がデフォルトである
  • Biome
    • もともとRomeだった
      • フロントエンドツールチェインの大統一を目指してた
      • ASTいじる系をまとめてやる
    • linterとformatter両方入ってて高速
      • prettierの課題を解決してる

PrettierとBiomeを比較して

  • アルゴリズム
    • 全く同じものを使ってる
    • かなり高い互換性
  • パフォーマンス(単一ファイル)
    • Biomeが速い
  • パフォーマンス(複数ファイル)
    • Biomeが速いしPrettierが遅い
    • Prettierの改善の余地があるところ
  • linterとのインテグレーション
    • Biomeは楽でPrettierは大変
  • ESLintとのインテグレーション
    • どっちも大変
  • サポート言語
    • Biomeは限定的(JS系/JSON系)
    • Prettierはすごく多い
      • 世の中にあるパーサーを活用できるから範囲が広い
  • プラグイン
    • Biomeはまだ対応してない
  • 言語
    • BiomeはrustでPrettierはJS

Prettierの今後

  • 今後も価値を提供し続けられること
  • 注力すべきポイント
    • 手軽さ
      • ESLintとの連携
    • パフォーマンス
      • Biomeに匹敵するレベルは難しい
      • 言語スイッチしないレベルでやれることをまず進める

Documentation testsの恩恵

Documentation tests

  • コメントの中にassert書いてテストする
    • @exampleで書ける
  • ドキュメントに書いたコードの動作を保証できる
    • READMEに書いてあるサンプルが動かない、なんてことにならない
  • 動作保証されたサンプル
  • JSDocにふれる機会が増える
  • モックが必要だったりするテストは書けない
  • vite-plugin-doctestとvitest入れれば使える

Full TypeScriptだから実現できる世界線

  • k-ichirofさん

フルTypeScript

  • FE/BE/インフラをtsで
  • 向いている環境
    • 規模小さめ
      • 1人やめただけでも影響が大きい
    • フルスタックに動く
    • ジュニア多め

Real World Type Puzzle and Code Generation