ProxyとTypeScriptのおいしい関係

@TSKaigi2025

自己紹介

name: Motoki Shakagori
screenName: ほとけ
org: 株式会社ベースマキナ

https://linktr.ee/mshaka

伝えたいこと

ProxyとTypeScriptの型を組み合わせると、「動的なプログラムの自由度の高さ」と「型のサポート」の両方を享受できる!

Proxyとは

  • ECMAのAPIの一つ
  • オブジェクトのプロパティアクセスに介入できる(「動的」と言っているのはこれ)
const names = { John: 'John', Mary: 'Mary' }
const greeting = new Proxy(names, {
  get(target, prop) {
    const original = target[prop]
    return original ? 'Hello, ' + original : 'Who are you?'
  }
})
console.log(greeting.John) // Hello, John
console.log(greeting.foo) // Who are you?

自由度が高いのでそのままだと型はガバガバ

const names = { John: 'John', Mary: 'Mary' }
const proxiedJohn: string = new Proxy(names, {
get() {
    return 0 // number type
  }
}).John

Proxyの活用例: Conform

デモ

コード

  • useFormにフォーム要素の型を渡すだけで、fieldsfullNameというキーが存在するという扱いになる
  • Why?🤔🤔🤔

中身はProxy

fieldsProxyでラップされているので、実はfullName以外のアクセスもできる(ただし型エラー)

  const [form, fields] = useForm<{ fullName: string }>({})
  console.log(fields.foo.value) // ランタイムではエラーにならない

内部実装イメージ

new Proxy({} as any, {
  get(target, key) {
    // form内のフィールドの現在の状態を取得
    // keyと一致するname属性の要素があればその値が返ってくる
  }
}) as FormMetaData<{ fullName: string }>

* 実際の実装はもっと複雑です

Recap: 何が嬉しい?

  • ライブラリ作者視点: 「動的なプログラムの自由度の高さ」と「型のサポート」の両方を享受できる!
    • しかも型だけ大嘘こいているわけでもない(特定のプロパティしか見せていないだけ)
  • ユーザー視点: 仕組みとして賢く、しかも書いていて気持ちいい😇

同様にProxyを活用しているライブラリ

Thank you!

宣伝: 来月の関数型まつりでも登壇します!