3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SvelteAdvent Calendar 2024

Day 16

+page.svelteの型の再利用のアイデア

Last updated at Posted at 2024-12-15

前提

  • デザイナーはTypeScriptに詳しくない
  • リリース後の運用(UIの変更など)をデザイナーが行う

+page.svelte

SvelteKitではroutesディレクトリ配下に+page.svelteを配置するとページを作成することができます。

また、+page.svelteはただのSvelteコンポーネントなので他のファイルからimportすることができます。
この記事はそれを利用してみる内容となっています。

特定のページでしか使用しないコンポーネント

今回例としてLPのようなページを考えます。このLPは他のページと完全に独立しています。
また、lp/_components/に配置したPosts.sveltelp/+page.server.tslp/+page.svelteでしか使用しないものとします。

このような状況ではlpディレクトリの近くにPosts.svelteを置くのがいいと考えています。
今後共通で使用することがないとわかっている、かつ他で使って欲しくないコンポーネントを離れた別の場所に置きたくないためです。

この状況下ではPostsコンポーネントのpropsに関しても

+page.server.ts -> +page.svelte -> Posts.svelte

と流れてくる以外ないので、Posts.svelteコンポーネントのpropsの型も+page.svelteから持ってきてしまってよいでしょう。

つまりこうです。

Posts.svelte
<script lang="ts">
	import type { ComponentProps } from 'svelte';
	import type Page from '../+page.svelte';

	type PageDataPosts = ComponentProps<typeof Page>['data']['posts'];
	let { posts }: { posts: PageDataPosts } = $props();
</script>

+page.server.tsは以下です。

+page.server.ts
declare const __brand: unique symbol;
type BrandedType<T, B> = T & { [__brand]: B };

type PostId = BrandedType<number, 'id'>;
type UserId = BrandedType<number, 'userId'>;

type Post = {
	id: PostId;
	title: string;
	body: string;
	userId: UserId;
};

type PageServerData = {
	posts: Post[];
};
export const load = async (): Promise<PageServerData> => {
	const posts = await fetch('https://jsonplaceholder.typicode.com/posts/').then(
		(response) => response.json()
	);
	return {
		posts: posts.slice(0, 10),
	};
};

Post型のiduserIdにはBrandedTypeを使用しておりかつその型をexportしていないので、
今後例えばPosts.svelteを拡張したXXXPosts.svelteを「TypeScriptに詳しくないデザイナー」が作成した時に既存のPosts.sveltepropsを見に行くように誘導できるので少し安心です。

また、Posts.svelteprops+page.svelteの型を使用することによって、このコンポーネントが+page.svelteのデータを表示することを明示できました。

まとめ

このような使い方をする機会はあまりないと思いますが、+page.svelteの型の再利用や+page.svelteをStorybookで表示するなどのテクニックとして覚えておいて損はありません。

個人的には+page.svelte+layout.svelteに色々書きすぎるとStorybookでの表示やテストの時にしんどくなると思っており、Page.svelteLayout.svelteコンポーネントを作って+page.svelteはそのページのPage.svelteを読み込んでいるだけ、+layout.svelteは極力使用しない という選択肢もありだと思っています。

この記事はこういうこともできるよ というアイデア、知識として読んでもらえればと思います。
最後まで読んでくださりありがとうございました!

みなさんのちょっと変わったSvelteKit、Svelteの使い方の記事も読みたいのでぜひ書いてください🙏

ページやソース

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?