SuperformsのProxy objectsは何ができるのか
SveltekitのフォームライブラリであるSuperformsを使った開発の中でProxy objectsを利用する機会がありました。その際いろいろと触って確認したことを備忘録として残しておきます。
「Proxy objectsって何に使えるの??」な人の参考になれば幸いです。
※Superformsの基本的な使い方がわかる方を想定しているため、Superformsの詳細については記載しません。
Superforms とは
Sveltekitのフォームライブラリです。フォームのバリデーション等をサポートしてくれます。
Proxy objects とは
ざっくり言うと、対応するフォームデータとの双方向更新や片方向のデータ変換をしてくれるオブジェクトです。
DateProxyを例にすると、Date型のフォームデータにnew Date('2024-10-01T00:00:00.000Z')
と設定したら、それに対応するProxyからは2024/10/01
の文字列が取得できます。逆に、Proxyに2024/10/01
の文字列を設定したら、フォームデータのDate型に2024/10/01
が設定されます。めっちゃ便利。
ちなみに私はProxy objectsの存在を知るまで頑張って双方向変換を実現しようとして無限ループさせたり力技実装したりと時間を無駄にしたので同じ苦しみを味わう人が減って欲しい・・・笑
Superformsには現時点で以下のプロキシが用意されています。
基本的に指定したフォームフィールドに対する書き込み可能なストアが返却されます。
import {
// The primitives return a Writable<string>:
booleanProxy,
dateProxy,
intProxy,
numberProxy,
stringProxy,
// File proxies
fileProxy,
fileFieldProxy, // formFieldProxy
// File[] proxies
filesProxy,
filesFieldProxy, // arrayProxy
// The type of the others depends on the field:
formFieldProxy,
arrayProxy,
fieldProxy
} from 'sveltekit-superforms';
ここからはそれぞれのプロキシについて見ていきましょう。
各オプションの説明には、どっち方向で動作するかも記載しています。
※taint
オプションはproxy以外で使われる場合と動作が変わらないため取り上げません。
私が検証した時のコードも貼っておくので参考までにどうぞ。
booleanProxy
boolean型に対するプロキシです。string型のストアになっています。
import { superForm, booleanProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = booleanProxy(form, 'field', { options });
{
trueStringValue = 'true';
taint?: boolean | 'untaint' | 'untaint-form';
}
trueStringValue オプション($form → $proxy)
$form.field
がtrue
の場合に、指定された文字列が$proxy
に設定されます。
$form.field
がfalse
の場合は、$proxy
は空文字になります。
$proxy
に対してtrueStringValueオプションに指定した文字列を入力した時に$form.field
がtrue
になるオプションではありません。$proxy
に何らかの文字列を入れれば通常のbooleanと同じくtrue
、空文字であればfalse
になります。
ユースケースとしては有効にするしないの選択項目などに使えるのではないでしょうか。
<script>
const proxy = booleanProxy(form, 'field', { trueStringValue: '1' });
</script>
<input type="radio" value="1" bind:group={$proxy} />
<input type="radio" value="" bind:group={$proxy} />
dateProxy
date型に対するプロキシです。string型のストアになっています。
import { superForm, dateProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = dateProxy(form, 'field', { options });
{
format:
// Extract the part of the date as a substring:
| 'date' | 'datetime' | 'time'
// Convert the date to UTC:
| 'date-utc' | 'datetime-utc' | 'time-utc'
// Convert the date to local time:
| 'date-local' | 'datetime-local' | 'time-local'
// The default ISODateString:
| 'iso' = 'iso';
empty?: 'null' | 'undefined';
taint?: boolean | 'untaint' | 'untaint-form';
}
format オプション($form → $proxy)
$form.field
の値をどのような文字列に変換するかを指定するオプションです。
それぞれのオプションを設定したときに$proxy
に設定される値を記載します。
以下の例では$form.field = new Date('2024-10-01T00:00:00.000Z')
が設定されているものとします。ブラウザ側はJSTです。
option | $proxy |
---|---|
iso |
'2024-10-01T00:00:00.000Z' |
date |
'2024-10-01' |
datetime |
'2024-10-01T00:00' |
time |
'00:00' |
date-utc |
'2024-10-01' |
datetime-utc |
'2024-10-01T00:00' |
time-utc |
'00:00' |
date-local |
'2024-10-01' |
datetime-local |
'2024-10-01T09:00' |
time-local |
'09:00' |
プロキシに限った話ではありませんが、日付を扱う場合にはタイムゾーンに気をつけて扱いましょう!
empty オプション($form ← $proxy)
$proxy
に空文字を入力した際に$form.field
に設定される値を指定します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
intProxy
number型に対するプロキシです。string型のストアになっています。
少数を扱う場合はnumberProxyを利用しましょう。
オプションで特殊な変換をしない限りは、基本的にbind:value
で事足りると思います。
(文字列-数値間の変換程度であれば自動で行なってくれるためです)
import { superForm, intProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = intProxy(form, 'field', { options });
{
empty?: 'null' | 'undefined' | 'zero';
initiallyEmptyIfZero?: boolean;
taint?: boolean | 'untaint' | 'untaint-form';
}
empty オプション($form ← $proxy)
$proxy
に空文字を入力した際に$form.field
に設定される値を指定します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
{ empty: 'zero' } |
'' (空文字) |
0 |
initiallyEmptyIfZero オプション($form → $proxy)
$form.field
の値が0
の場合に空文字に変換するか、0のままにするかのオプションです。
初期値に0を入れておきたいがプレースホルダーをユーザーに見せたい時に有効化すると良いでしょう。
option | $form.field | $proxy |
---|---|---|
{ initiallyEmptyIfZero: true } |
0 |
'' (空文字) |
{ initiallyEmptyIfZero: false } |
0 |
0 |
numberProxy
number型に対するプロキシです。string型のストアになっています。
正数のみを扱う場合はintProxyを利用しましょう。
オプションで特殊な変換をしない限りは、基本的にbind:value
で事足りると思います。
(文字列-数値間の変換程度であれば自動で行なってくれるためです)
import { superForm, numberProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = numberProxy(form, 'field', { options });
{
empty?: 'null' | 'undefined' | 'zero';
initiallyEmptyIfZero?: boolean;
delimiter?: "." | "," | undefined;
taint?: boolean | 'untaint' | 'untaint-form';
}
empty オプション($form ← $proxy)
$proxy
に空文字を入力した際に$form.field
に設定される値を指定します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
{ empty: 'zero' } |
'' (空文字) |
0 |
initiallyEmptyIfZero オプション($form → $proxy)
$form.field
の値が0
の場合に空文字に変換するか、0のままにするかのオプションです。
初期値に0を入れておきたいがプレースホルダーをユーザーに見せたい時に有効化すると良いでしょう。
option | $form.field | $proxy |
---|---|---|
{ initiallyEmptyIfZero: true } |
0 |
'' (空文字) |
{ initiallyEmptyIfZero: false } |
0 |
0 |
delimiter オプション($form ← $proxy)
少数の区切り文字を指定するオプションです。「.」を指定した場合に「,」を入力した場合には以降の値は切り捨てられますが、「,」を指定した場合は「,」以降は少数として扱われます。小数点をカンマで区切る国の場合、設定すると良いでしょう。
option | $proxy | $form.field |
---|---|---|
{ delimiter: '.' } |
123.45 |
123.45 |
{ delimiter: '.' } |
123,45 |
123 |
{ delimiter: ',' } |
123.45 |
123.45 |
{ delimiter: ',' } |
123,45 |
123.45 |
stringProxy
string型に対するプロキシです。string型のストアになっています。
空文字の変換処理が不要な場合は、基本的にbind:value
で事足りると思います。
import { superForm, stringProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = stringProxy(form, 'field', { options });
{
empty: 'null' | 'undefined';
taint?: boolean | 'untaint' | 'untaint-form';
}
empty オプション($form ← $proxy)
$proxy
に空文字を入力した際に$form.field
に設定される値を指定します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
{ empty: 'zero' } |
'' (空文字) |
0 |
arrayProxy
array型のプロキシです。該当フィールドに対する各種オブジェクト返します。
今まで見てきたProxyと異なりsuperformオブジェクトを引数に渡す必要があります。
<script lang="ts">
import { superForm, arrayProxy } from 'sveltekit-superforms';
export let data;
const superform = superForm(data.form); // The whole superForm object is required
const { form } = superform; // Deconstruct as usual here
const { path, values, errors, valueErrors } = arrayProxy(superform, 'field');
</script>
{
taint?: boolean | 'untaint' | 'untaint-all';
}
path, values, errors, valueErrors が利用できます。
説明 | |
---|---|
path | 該当proxyのpath |
values(ストア) | proxy先の配列 |
errors(ストア) | 配列自体のエラー(例:配列内で最低2件選ばなければならないバリデーションエラーなど) |
valueErrors(ストア) | 配列内のデータに対するエラー(例:配列内のデータは2文字以上でなければならないバリデーションエラーなど) |
formFieldProxy
汎用的なプロキシです。該当フィールドに対する各種オブジェクト返します。
こちらもsuperformオブジェクトを引数に渡す必要があります。
※配列のフィールドはこのproxyで使用できないため、arrayProxyを使いましょう。もしくはindex付きの表記であれば配列内の任意のindexに対するproxyにすることができます。(例: field[0]
)
<script lang="ts">
import { superForm, formFieldProxy } from 'sveltekit-superforms';
export let data;
const superform = superForm(data.form); // The whole superForm object is required
const { form } = superform; // Deconstruct as usual here
const { path, value, errors, constraints, tainted } = formFieldProxy(superform, 'field');
</script>
{
taint?: boolean | 'untaint' | 'untaint-all';
}
path, value, errors, constraints, tainted が利用できます。
説明 | |
---|---|
path | 該当proxyのpath |
value(ストア) | proxy先の値 |
errors(ストア) | proxy先のエラー |
constraints(ストア) | スキーマからマップされた検証プロパティを持つオブジェクト https://superforms.rocks/concepts/client-validation#constraints |
tainted(ストア) | 変更されているか |
なお、このプロキシを使って汎用的なテキストコンポーネントを作成することもできます。
fieldProxy
汎用的なプロキシです。指定したフィールドのデータ型そのままのストアになっています。
例えばフィールドがbooleanであればプロキシもbooleanになるようです。
import { superForm, stringProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = stringProxy(form, 'field', { options });
{
empty: 'null' | 'undefined';
taint?: boolean | 'untaint' | 'untaint-form';
}
empty オプション($form ← $proxy)
$proxy
に空文字を入力した際に$form.field
に設定される値を指定します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
fileProxy
FileList
型のプロキシです。
mutipulで複数選択しても1個しか値は取れません。その場合はfilesProxyやfilesFieldProxyを利用しましょう。
import { superForm, fileProxy } from 'sveltekit-superforms';
export let data;
const { form } = superForm(data.form);
const proxy = fileProxy(form, 'field', { options });
{
empty?: 'null' | 'undefined';
taint?: boolean | 'untaint' | 'untaint-form';
}
empty オプション($form ← $proxy)
$proxy
に空文字を設定した際に$form.field
に設定する値を指定します。
※ファイル選択でキャンセルし、ファイル選択状態がクリアされた場合などに動作します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
fileFieldProxy
ファイルのプロキシです。該当フィールドに対する各種オブジェクト返します。
mutipulで複数選択しても1個しか値は取れません。その場合はfilesProxyやfilesFieldProxyを利用しましょう。
<script lang="ts">
import type { SampleScheme } from '$lib/schemas';
import SuperDebug, { fileFieldProxy } from 'sveltekit-superforms';
import type { SuperForm, SuperFormData } from 'sveltekit-superforms/client';
export let data;
const superform = superForm(data.form);
const { path, value, errors, constraints } = fileFieldProxy(superform, 'fileFieldProxy', { options });
</script>
{
empty?: 'null' | 'undefined';
taint?: boolean | 'untaint' | 'untaint-form';
}
path, value, errors, constraints, tainted が利用できます。
説明 | |
---|---|
path | 該当proxyのpath |
value(File|FileList 型のストア) |
proxy先の値 |
errors(ストア) | proxy先のエラー |
constraints(ストア) | スキーマからマップされた検証プロパティを持つオブジェクト https://superforms.rocks/concepts/client-validation#constraints |
tainted(ストア) | 変更されているか |
empty オプション($form ← $proxy)
$proxy
に空文字を設定した際に$form.field
に設定する値を指定します。
※ファイル選択でキャンセルし、ファイル選択状態がクリアされた場合などに動作します。
option | $proxy | $form.field |
---|---|---|
{ empty: 'null' } |
'' (空文字) |
null |
{ empty: 'undefined' } |
'' (空文字) |
undefined |
filesProxy
FileList
型のプロキシです。
mutipulで複数選択にも対応しています。
<script lang="ts">
import { superForm, formFieldProxy } from 'sveltekit-superforms';
export let data;
const superform = superForm(data.form);
const proxy = filesProxy(superform, 'field');
</script>
fileFieldsProxy
arrayProxyのファイル版で基本的には同じです。
<script lang="ts">
import { superForm, fileFieldsProxy } from 'sveltekit-superforms';
export let data;
const superform = superForm(data.form);
const { path, values, errors, valueErrors } = arrayProxy(superform, 'field');
</script>
path, values, errors, valueErrors が利用できます。
説明 | |
---|---|
path | 該当proxyのpath |
values(FileList 型のストア) |
proxy先の配列値 |
errors(ストア) | 配列自体のエラー |
valueErrors(ストア) | 配列内のデータに対するエラー |
終わりに
Proxy objectsを使うことで煩雑な変換処理を書かずに済み、今後の開発効率が上がりそうですね。
これから使われる方の参考になれば幸いです。
素敵なSuperformsライフをお過ごしください!
Discussion