🖇️
@tanstack/react-virtual を使おうとしたら TypeScript の型推論で詰まった話
Reactで大量のデータをリスト表示する際に有効なバーチャルリスト用ライブラリーである @tanstack/react-virtual
を使おうとしたら、TypeScript の型推論が効かなくなる壁に当たったので解決策を含めたメモをここに残します。
本題
問題となったのは以下のようなコードです。まずは型定義から。
type Fuga = {
id: string
name: string
...
}
type Piyo = {
id: string
name: string
...
}
type FugaItem = {
type: 'fuga'
value: Fuga
}
type PiyoItem = {
type: 'piyo'
value: Piyo
}
type Item = FugaItem | PiyoItem
上記の Item
型の配列を @tanstack/react-virtual
の useVirtualizer()
を使って、 Item.type
ごとに表示する項目を出し分けたいとします。
const App = () => {
const { data: items } = useHogeQuery() // items の型は Item[]
const parentRef = React.useRef()
const rowVirtualizer = useVirtualizer({
const : items.length,
getScrollElement: () => scrollableNodeRef.current,
estimateSize: () => 100,
})
return (
{rowVirtualizer.getVirtualItems().map((row) => (
<div
key={row.key}
data-index={row.index}
ref={rowVirtualizer.measureElement}
>
{items[row.index].type === 'fuga' && <FugaRow key={items[row.index].id} fuga={items[row.index].value} />}
{items[row.index].type === 'piyo' && <PiyoRow key={items[row.index].id} piyo={items[row.index].value} />}
</div>
)}
)
}
このままだと、 items[row.index].type === ...
以降の項で、 items[row.index]
の型が FugaItem
なのか、PiyoItem
なのかが絞り込まれず、静的解析エラーとなってしまいます。
(自分が調べた範囲ではこの現象の名前を確認することはできませんでした🥺 ご存知の方コメントいただけますと幸いです)
解決策
次のように修正することで、fuga={items[row.index].value}
などの部分で型推論が効かない問題を解決できます。
const App = () => {
...
return (
{rowVirtualizer.getVirtualItems().map((row) => {
// 配列の要素を直接参照するのではなく、変数に一度格納する
const item = items[row.index]
return (
<div
key={row.key}
data-index={row.index}
ref={rowVirtualizer.measureElement}
>
{item.type === 'fuga' && <FugaRow key={item.id} fuga={item.value} />}
{item.type === 'piyo' && <PiyoRow key={item.id} piyo={item.value} />}
</div>
)
}}
)
}
終わりに
今回は 前回書いた記事 を踏まえた内容となりました。
毎回書くタイトルが具体的すぎるのでもう少し抽象度を上げたいのですが、それだと見返した時に何が嬉しいのか分からなくなるな〜となり悩んでます。次はもっとシンプルに書けるよう努めます。
ありがとうございました。
Discussion