Skip to main content

Types

Generated types

The RequestHandler and Load types both accept a Params argument allowing you to type the params object. For example this endpoint expects foo, bar and baz params:

src/routes/[foo]/[bar]/[baz]/+server
/**
 * @type {import('@sveltejs/kit').RequestHandler<{
 *   foo: string; *   bar: string; *   baz: string * }>} */export async function GET({ params }) {
	// ...}
import type { RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler<{
  foo: string;
  bar: string;
  baz: string
}> = async ({ params }) => {
	// ...};

Needless to say, this is cumbersome to write out, and less portable (if you were to rename the [foo] directory to [qux], the type would no longer reflect reality).

To solve this problem, SvelteKit generates .d.ts files for each of your endpoints and pages:

.svelte-kit/types/src/routes/[foo]/[bar]/[baz]/$types.d
import type * as Kit from '@sveltejs/kit';

type RouteParams = {
	foo: string;
	bar: string;
	baz: string;
};

export type RequestHandler = Kit.RequestHandler<RouteParams>;
export type PageLoad = Kit.Load<RouteParams>;

These files can be imported into your endpoints and pages as siblings, thanks to the rootDirs option in your TypeScript configuration:

src/routes/[foo]/[bar]/[baz]/+server
/** @type {import('./$types').RequestHandler} */
export async function GET({ params }) {
	// ...}
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
	// ...};
src/routes/[foo]/[bar]/[baz]/+page
/** @type {import('./$types').PageLoad} */
export async function load({ params, fetch }) {
	// ...}
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params, fetch }) => {
	// ...};

The return types of the load functions are then available through the $types module as PageData and LayoutData respectively, while the union of the return values of all Actions is available as ActionData.

Starting with version 2.16.0, two additional helper types are provided: PageProps defines data: PageData, as well as form: ActionData, when there are actions defined, while LayoutProps defines data: LayoutData, as well as children: Snippet.

src/routes/+page
<script>
	/** @type {import('./$types').PageProps} */
	let { data, form } = $props();
</script>
<script lang="ts">
	import type { PageProps } from './$types';

	let { data, form }: PageProps = $props();
</script>
Legacy mode

Before 2.16.0:

src/routes/+page
<script>
	/** @type {{ data: import('./$types').PageData, form: import('./$types').ActionData }} */
	let { data, form } = $props();
</script>
<script lang="ts">
	import type { PageData, ActionData } from './$types';

	let { data, form }: { data: PageData, form: ActionData } = $props();
</script>

Using Svelte 4:

src/routes/+page
<script>
  /** @type {import('./$types').PageData} */
  export let data;
  /** @type {import('./$types').ActionData} */
  export let form;
</script>
<script lang="ts">
	import type { PageData, ActionData } from './$types';

  
  export let data: PageData;
  
  export let form: ActionData;
</script>

For this to work, your own tsconfig.json or jsconfig.json should extend from the generated .svelte-kit/tsconfig.json (where .svelte-kit is your outDir):

{ "extends": "./.svelte-kit/tsconfig.json" }

Default tsconfig.json

The generated .svelte-kit/tsconfig.json file contains a mixture of options. Some are generated programmatically based on your project configuration, and should generally not be overridden without good reason:

.svelte-kit/tsconfig
{
	"compilerOptions": {
		"paths": {
			"$lib": ["../src/lib"],
			"$lib/*": ["../src/lib/*"]
		},
		"rootDirs": ["..", "./types"]
	},
	"include": [
		"ambient.d.ts",
		"non-ambient.d.ts",
		"./types/**/$types.d.ts",
		"../vite.config.js",
		"../vite.config.ts",
		"../src/**/*.js",
		"../src/**/*.ts",
		"../src/**/*.svelte",
		"../tests/**/*.js",
		"../tests/**/*.ts",
		"../tests/**/*.svelte"
	],
	"exclude": [
		"../node_modules/**",
		"../src/service-worker.js",
		"../src/service-worker/**/*.js",
		"../src/service-worker.ts",
		"../src/service-worker/**/*.ts",
		"../src/service-worker.d.ts",
		"../src/service-worker/**/*.d.ts"
	]
}

Others are required for SvelteKit to work properly, and should also be left untouched unless you know what you’re doing:

.svelte-kit/tsconfig
{
	"compilerOptions": {
		// this ensures that types are explicitly
		// imported with `import type`, which is
		// necessary as Svelte/Vite cannot
		// otherwise compile components correctly
		"verbatimModuleSyntax": true,

		// Vite compiles one TypeScript module
		// at a time, rather than compiling
		// the entire module graph
		"isolatedModules": true,

		// Tell TS it's used only for type-checking
		"noEmit": true,

		// This ensures both `vite build`
		// and `svelte-package` work correctly
		"lib": ["esnext", "DOM", "DOM.Iterable"],
		"moduleResolution": "bundler",
		"module": "esnext",
		"target": "esnext"
	}
}

Use the typescript.config setting in svelte.config.js to extend or modify the generated tsconfig.json.

$lib

This is a simple alias to src/lib. It allows you to access common components and utility modules without ../../../../ nonsense.

$lib/server

A subdirectory of $lib. SvelteKit will prevent you from importing any modules in $lib/server into client-side code. See server-only modules.

app.d.ts

The app.d.ts file is home to the ambient types of your apps, i.e. types that are available without explicitly importing them.

Always part of this file is the App namespace. This namespace contains several types that influence the shape of certain SvelteKit features you interact with.

It’s possible to tell SvelteKit how to type objects inside your app by declaring the App namespace. By default, a new project will have a file called src/app.d.ts containing the following:

declare global {
	namespace App {
		// interface Error {}		// interface Locals {}		// interface PageData {}		// interface PageState {}		// interface Platform {}	}
}

export {};

The export {} line exists because without it, the file would be treated as an ambient module which prevents you from adding import declarations. If you need to add ambient declare module declarations, do so in a separate file like src/ambient.d.ts.

By populating these interfaces, you will gain type safety when using event.locals, event.platform, and data from load functions.

Error

Defines the common shape of expected and unexpected errors. Expected errors are thrown using the error function. Unexpected errors are handled by the handleError hooks which should return this shape.

interface Error {/*…*/}
message: string;

Locals

The interface that defines event.locals, which can be accessed in server hooks (handle, and handleError), server-only load functions, and +server.js files.

interface Locals {}

PageData

Defines the common shape of the page.data state and $page.data store - that is, the data that is shared between all pages. The Load and ServerLoad functions in ./$types will be narrowed accordingly. Use optional properties for data that is only present on specific pages. Do not add an index signature ([key: string]: any).

interface PageData {}

PageState

The shape of the page.state object, which can be manipulated using the pushState and replaceState functions from $app/navigation.

interface PageState {}

Platform

If your adapter provides platform-specific context via event.platform, you can specify it here.

interface Platform {}

Edit this page on GitHub llms.txt

previous next