As brunnerh notes, there isn't currently (as of writing this) a good way to take the strongly-typed component/endpoint, and pass its definition to the other. In the past, I've used the endpoint to store a "response" interface, which can easily be imported by co-located components.
// +server.ts
import { json } from '@sveltejs/kit';
export const GET = async () => {
// ...
return json({ type: "success", msg: "Hello, world!" } satisfies _res);
// ^ typed
};
export type _res = {
type: "success" | "error";
msg: string;
};
<!-- Component.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import type { _res } from './endpoint/+server';
let text = '';
onMount(async () => {
const res = await fetch('/version/endpoint');
const obj: _res = await res.json();
//^ typed
text = obj.msg;
});
</script>
{text}
Note on modern SvelteKit
I generally avoid fetching inside components, as it is usually messy.
In most cases, you can get away with data loading for GET, and form actions for POST. load()
is strongly typed, thanks to codegen.
Once inside your component, you can achieve strong-typing by either:
- creating an interface (following the example above)
- importing the type from the page function:
<script lang="ts">
import type { load } from './+page';
export let data: Awaited<ReturnType<typeof load>>;
//^ let data: { type: "success" | "error"; msg: string; }
</script>
You can return custom JSON in form actions, but it's not currently strongly typed. You have the option to combine data loading and form actions to achieve this, by migrating your API "response" logic into load()
:
form submitted -> server action -> invalidateAll()
-> load()
re-ran -> page updated