☠️

【Supabase × TypeScript】JavaScript Client Libraryでデータを取得する際に遭遇する落とし穴と対策

2023/09/24に公開

はじめに

この記事は、Supabaseを使ってWebアプリを作成したことがある方を対象としています。

現象は以下のバージョンで再現します。

package.json
"@supabase/supabase-js": "^2.33.2"

SupabaseのJavaScript Client Libraryとは

https://supabase.com/docs/reference/javascript/introduction

例えば、以下のSQL処理は

select id, title, content from articles;

JavaScript Client Libraryを使うことによって

const { data: articles, error } = await supabase
  .from('articles')
  .select('id,title,content');

と書けます。

遭遇した落とし穴

欲しいデータが動的に変わる場合があったとして、以下のように書きたくなることがあるかもしれません。

let fields = 'id,title,content1';

const session = await getSession();

// ログイン済みの場合
if (session) {
  fields += ',content2';
}

const { data: article, error } = await supabase
  .from('articles')
  .select(fields)
  .eq('slug', params.slug)
  .single();

一見何も問題ないように見えますが、articleの型を確認すると、GenericStringErrorとなっています。

Issueのやり取りを見ていくと、Supabaseの中の人が以下のように回答しています。
https://github.com/supabase/supabase-js/issues/551#issuecomment-1246189359

select()に渡された実引数が文字列リテラルではなく文字列変数の場合、正しく機能しないとのことです。
中の人はselect(fields as any)とすることで回避できると説明していますが、これをやっても解決しません。

解決策

as anyではなくas '*'とすることで解決します。
これについて、Issueでも扱いづらさが指摘されています。

const { data: article, error } = await supabase
  .from('articles')
  .select(fields as '*')
  .eq('slug', params.slug)
  .single();

https://github.com/supabase/supabase-js/issues/551#issuecomment-1493284837

Discussion