vue-tsc v2.2.0からv2.2.2にアップデートした際にuseSlotを使ったコードで以下のようなエラーが発生した。
app/frontend/components/ui/Card.vue:27:7 - error TS7022: 'slots' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. 27 const slots = useSlots(); app/frontend/components/ui/Card.vue:28:7 - error TS7022: 'hasHeader' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. 28 const hasHeader = !!slots.header;
useSlotsで指定したスロットがundefinedかどうかを判定するために!!を使っているが、useSlotsの戻り値がany型になっているためエラーが発生している模様。
確かにuseSlotsの型はanyになっている。
useSlots()
Context から slots オブジェクトを返します。これは Setup Context オブジェクトが利用できない
<script setup>での利用を意図しています。function useSlots(): Record<string, (...args: any[]) => VNode[]>TypeScript を使用する場合は、代わりに defineSlots() を優先すべきです。
vue-tscの以下のようなslot周りの型チェックの改善されてanyを検知できるようになった?
対応方法としては、defineSlotsを使って型を指定すれば問題なかった。
defineSlots() は型パラメーターのみを受け取り、実行時引 数はありません。 型パラメーターは、プロパティキーがスロット名で、値の型 がスロット関数である型リテラルでなければなりません。 関数の最初の引数はスロットが受け取ることを期待する props で、その型はテンプレート内のスロット props に使用されることになります。 戻り値の型は現在無視されており、any を指定することがで きますが、将来的にはスロットの内容チェックのために活用するか もしれません。 https://ja.vuejs.org/api/sfc-script-setup#defineslots
以下のような感じで返り値の型を指定できる。(戻り値は無視されるので何でも良い)
- const slots = useSlots(); + const slots = defineSlots<{ + header(): unknown; + }>();
基本的に<script setup>でTypeScriptを使っている場合はdefineSlotsを使うのが推奨なんですね📝
あとそもそも今回のようなslotを渡しているかどうかの判断してtemplateの表示を切り替えるだけだったらv-if="$slot.header"でも良さそうだった。
条件付きスロット スロットにコンテンツが渡されたかどうかに基づいて何かをレンダリングしたい場合があります。 これを実現するには、
$slotsプロパティとv-ifを組み合わせて使用します。https://ja.vuejs.org/guide/components/slots#conditional-slots