Svelte入門:リファレンス @sveltejs/kit -Vol.18-

スポンサーリンク
Svelte入門: リファレンス @sveltejs/kit -Vol.18- 用語解説
Svelte入門: リファレンス @sveltejs/kit -Vol.18-
この記事は約11分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、SvelteKitのリファレンスについて解説しています。

スポンサーリンク

背景

SvelteKitのリファレンスについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。

@sveltejs/kit

SubmitFunction

type SubmitFunction
	Success extends
		| Record<string, unknown>
		| undefined = Record<string, any>,
	Failure extends
		| Record<string, unknown>
		| undefined = Record<string, any>
> = (input: {
	action: URL;
	formData: FormData;
	formElement: HTMLFormElement;
	controller: AbortController;
	submitter: HTMLElement | null;
	cancel: () => void;
}) => MaybePromise
	| void
	| ((opts: {
			formData: FormData;
			formElement: HTMLFormElement;
			action: URL;
			result: ActionResult<Success, Failure>;
			/**
			 * フォーム送信レスポンスのデフォルトの動作を取得するには、これを呼び出します。
			 * @param options 成功した送信後に`<form>`の値をリセットしたくない場合は`reset: false`を設定します。
			 * @param invalidateAll 送信後にアクションが`invalidateAll`を呼び出さないようにしたい場合は`invalidateAll: false`を設定します。
			 */
			update: (options?: {
				reset?: boolean;
				invalidateAll?: boolean;
			}) => Promise<void>;
	  }) => MaybePromise<void>)
>;

解説

SubmitFunctionは、SvelteKitにおけるフォーム送信処理をカスタマイズするための型定義です。この型は、フォーム送信時の動作を制御するコールバック関数の構造を定義しています。

型パラメータ
  • Success: 成功したアクションの結果の型。デフォルトは Record<string, any>
  • Failure: 失敗したアクションの結果の型。デフォルトは Record<string, any>
入力パラメータ (input)

関数は次のプロパティを持つオブジェクトを受け取ります:

  • action: フォームの送信先URL
  • formData: 送信されるフォームデータ
  • formElement: 送信されるHTMLフォーム要素
  • controller: リクエストをキャンセルするために使用できるAbortController
  • submitter: フォーム送信を開始した要素(例:送信ボタン)
  • cancel: フォーム送信をキャンセルするための関数
戻り値

この関数は以下のいずれかを返すことができます:

  1. void – 処理を継続し、デフォルトの動作を実行
  2. コールバック関数 – フォーム送信処理の結果を受け取り、追加の処理を行う関数

このコールバック関数は以下のパラメータを受け取ります:

  • formData: 送信されたフォームデータ
  • formElement: フォーム要素
  • action: 送信先URL
  • result: アクションの結果(SuccessまたはFailure型)
  • update: デフォルトの送信後処理を実行する関数
    • reset: 成功時にフォームをリセットするかどうか(デフォルトはtrue
    • invalidateAll: 送信後に全てのデータを再検証するかどうか(デフォルトはtrue
使用例

この型は、SvelteKitのuse:enhanceディレクティブなどで使用され、フォーム送信の挙動をプログラムで制御できます。例えば:

<form
  method="POST"
  use:enhance={({ formData, cancel }) => {
    // 送信前の検証
    if (!isValid(formData)) {
      cancel();
      return;
    }
    
    // 送信後の処理
    return ({ result, update }) => {
      if (result.type === 'success') {
        // 成功時の追加処理
        showSuccessMessage();
        // デフォルト処理を実行(フォームリセットなど)
        return update();
      } else {
        // エラー処理
        showErrorMessage(result.error);
        // フォームをリセットせずにデータ再検証
        return update({ reset: false });
      }
    };
  }}
>
  <!-- フォーム内容 -->
</form>

この型定義により、SvelteKitアプリケーションでフォーム送信の前後に詳細なカスタム処理を追加できます。

Transport

バージョン2.11.0以降で利用可能

transportフックを使用すると、サーバー/クライアント境界を越えてカスタム型を転送できます。 各トランスポーターは、encodedecode関数のペアを持っています。サーバー側では、encodeは値がカスタム型のインスタンスであるかどうかを判断し、そうであれば、オブジェクトまたは配列になり得る、その値の非偽のエンコーディングを返します(そうでなければfalseを返します)。 ブラウザでは、decodeがエンコーディングをカスタム型のインスタンスに戻します。

import type { Transport } from '@sveltejs/kit';

declare class MyCustomType {
	data: any
}

// hooks.js
export const transport: Transport = {
	MyCustomType: {
		encode: (value) => value instanceof MyCustomType && [value.data],
		decode: ([data]) => new MyCustomType(data)
	}
};
type Transport = Record<string, Transporter>;

解説

Transportは、SvelteKit 2.11.0から導入された機能で、サーバーとクライアント間でカスタムJavaScriptクラスや型のインスタンスをシームレスに転送するためのメカニズムを提供します。

主要な概念
  1. 問題の背景: 通常、サーバーサイドレンダリング(SSR)やロード関数からクライアントに値を渡す際、JSON.stringifyを通してシリアライズされます。これは基本的なデータ型(オブジェクト、配列、プリミティブ値)には機能しますが、カスタムクラスのインスタンスなど複雑な型は適切に転送されません。
  2. Transportの役割: カスタムクラスやデータ型のインスタンスをサーバーからクライアントへ(またはその逆方向に)正しく転送するための変換ロジックを定義します。
使用方法

Transportは、次の2つの関数を持つトランスポーターオブジェクトをキーと値のペアとして格納するレコード型です:

  • encode関数: サーバー側で実行され、値がカスタム型のインスタンスかどうかを判断します
    • カスタム型のインスタンスであれば、そのデータを表す配列またはオブジェクトを返します
    • そうでなければ、falseを返します
  • decode関数: クライアント側で実行され、エンコードされたデータを元のカスタム型のインスタンスに変換します
実装例の解説
export const transport: Transport = {
  MyCustomType: {  // キーはトランスポーターの名前
    // サーバー側でMyCustomTypeインスタンスを識別してエンコード
    encode: (value) => value instanceof MyCustomType && [value.data],
    
    // クライアント側でエンコードされたデータからMyCustomTypeインスタンスを再構築
    decode: ([data]) => new MyCustomType(data)
  }
};
実用例

このフックは以下のような場面で特に役立ちます:

  1. 日付オブジェクト: DateオブジェクトをString型ではなく実際のDateインスタンスとしてクライアントに渡す
  2. カスタムクラス: データモデルのインスタンスをメソッドも含めてクライアントに転送する
  3. 特殊なデータ型: MapSetなど、JSONでは直接シリアライズできない型を転送する
設定場所

このtransportフックは通常、SvelteKitアプリケーションのhooks.js(またはhooks.ts)ファイルで定義され、アプリケーション全体でカスタム型の変換ロジックが一貫して適用されるようにします。

この機能によって、サーバーとクライアント間でのデータ転送が大幅に簡素化され、アプリケーションのコードがより自然に書けるようになります。

Transporter

transportフックのメンバー。

interface Transporter
	T = any,
	U = Exclude
		any,
		false | 0 | '' | null | undefined | typeof NaN
	>
> {…}
encode: (value: T) => false | U;
decode: (data: U) => T;

解説

Transporterインターフェースは、SvelteKitのtransportフックの各メンバーを定義するものです。このインターフェースは、カスタム型のインスタンスをサーバーとクライアント間で変換するための方法を提供します。

型パラメータ
  1. T: 変換する対象となるカスタム型。デフォルトはany
  2. U: エンコードされた値の型。デフォルトでは偽値(false, 0, '', null, undefined, NaN)以外のあらゆる値が許容されます
encode: (value: T) => false | U
  • 目的: サーバー側で、値がカスタム型Tのインスタンスかどうかを判断し、インスタンスである場合はシリアライズ可能な形式にエンコードします
  • 引数: カスタム型Tの可能性のある値
  • 戻り値:
    • 値が対象のカスタム型Tのインスタンスである場合: エンコードされたデータ(U型)
    • 値が対象のカスタム型Tのインスタンスでない場合: false
  • 注意: エンコード結果はJSONシリアライズ可能である必要があります(通常は配列やプレーンオブジェクト)
decode: (data: U) => T
  • 目的: クライアント側で、エンコードされたデータUを元のカスタム型Tのインスタンスに変換します
  • 引数: encode関数によって生成されたエンコードデータ(U型)
  • 戻り値: 復元されたカスタム型Tのインスタンス
使用例

例えば、Pointというカスタムクラスがあり、これをサーバーとクライアント間で転送したい場合:

class Point {
  constructor(public x: number, public y: number) {}
  
  distanceFromOrigin() {
    return Math.sqrt(this.x * this.x + this.y * this.y);
  }
}

// hooks.js/ts に定義するtransportフック
export const transport = {
  Point: {
    encode: (value) => value instanceof Point && [value.x, value.y],
    decode: ([x, y]) => new Point(x, y)
  }
};

この例では:

  • encode関数は値がPointのインスタンスである場合にxとy座標を配列として返します
  • decode関数はその配列から新しいPointインスタンスを作成します

これにより、サーバー側のロード関数から返されたPointオブジェクトが、クライアント側でもメソッドを含む完全なPointインスタンスとして利用できるようになります。

おわりに

今日は、 SvelteKitのリファレンスについて解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました