Vue3+TypeScriptで、provide/injectするのが思ったより簡単だったのでメモ。このページに辿り着いてる人はご存じだと思うので詳しい説明はスキップしますが、特定のコンポーネント以下でpropsのバケツリレーをしなくてもデータを受け渡しできる仕組みです。

Provide側

キーと値をprovide関数に渡します。キーは文字列でも良いですが、Symbolの方が使いやすそうなのでSymbolを使います。

InjectKeys.ts

import {InjectionKey, Ref} from 'vue';

export const MyInjectKey = Symbol() as InjectKey<Ref<string>>

リアクティブな ref<...> オブジェクトを渡す場合、 Ref<...> にしてください。

親コンポーネント

<script lang="ts" setup>
  import {provide, ref} from 'vue';
  import {MyInjectKey} from 'path/to/InjectKeys'

  const myValue = ref('hello');
  provide(MyInjectKey, myValue);
</script>

Injectされる側

子コンポーネント

<script lang="ts" setup>
  import {inject, PropType, watchEffect} from 'vue';
  import {MyInjectKey} from 'path/to/InjectKeys'

  const myValue = inject(MyInjectKey); // 正しく Ref<string> で伝播してくる
</script>

<template>
  <p> Received: {{ myValue }} </p>
</template>

この状態で、親コンポーネントで値が書き換えられても正しく反映されます。