From d7e60f515f5a9eb57d2735bdea2529e4341cfea4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 16:52:35 -0500 Subject: [PATCH 01/14] add a SvelteKit namespace for app-level types (#3569) --- packages/kit/test/apps/basics/src/app.d.ts | 15 ++++ .../apps/basics/src/routes/store/index.svelte | 10 ++- .../basics/src/routes/store/result.svelte | 4 +- packages/kit/types/ambient-modules.d.ts | 13 +++- packages/kit/types/helper.d.ts | 3 - packages/kit/types/page.d.ts | 71 ++++--------------- 6 files changed, 48 insertions(+), 68 deletions(-) create mode 100644 packages/kit/test/apps/basics/src/app.d.ts diff --git a/packages/kit/test/apps/basics/src/app.d.ts b/packages/kit/test/apps/basics/src/app.d.ts new file mode 100644 index 000000000000..06aacd5e3b51 --- /dev/null +++ b/packages/kit/test/apps/basics/src/app.d.ts @@ -0,0 +1,15 @@ +declare namespace SvelteKit { + interface Session { + answer: number; + calls: number; + } + + interface Stuff { + message: string; + error: string; + page: string; + value: number; + x: string; + y: string; + } +} diff --git a/packages/kit/test/apps/basics/src/routes/store/index.svelte b/packages/kit/test/apps/basics/src/routes/store/index.svelte index 43eb478eb39f..047138cbad77 100644 --- a/packages/kit/test/apps/basics/src/routes/store/index.svelte +++ b/packages/kit/test/apps/basics/src/routes/store/index.svelte @@ -7,12 +7,18 @@ let calls = 0; onMount(() => { - session.set(calls); + session.update(($session) => ({ + ...$session, + calls + })); }); const unsubscribe = page.subscribe(() => { calls++; - session.set(calls); + session.update(($session) => ({ + ...$session, + calls + })); }); onDestroy(unsubscribe); diff --git a/packages/kit/test/apps/basics/src/routes/store/result.svelte b/packages/kit/test/apps/basics/src/routes/store/result.svelte index f92ae29651e8..0adaf8f06c93 100644 --- a/packages/kit/test/apps/basics/src/routes/store/result.svelte +++ b/packages/kit/test/apps/basics/src/routes/store/result.svelte @@ -8,9 +8,9 @@ let calls = 0; onMount(() => { - calls = get(session); + ({ calls } = get(session)); });

Result

-

Calls: {calls}

\ No newline at end of file +

Calls: {calls}

diff --git a/packages/kit/types/ambient-modules.d.ts b/packages/kit/types/ambient-modules.d.ts index 264b9780ba28..969c4364b540 100644 --- a/packages/kit/types/ambient-modules.d.ts +++ b/packages/kit/types/ambient-modules.d.ts @@ -1,5 +1,12 @@ /* eslint-disable import/no-duplicates */ +declare namespace SvelteKit { + interface Locals {} + interface Platform {} + interface Session {} + interface Stuff {} +} + declare module '$app/env' { /** * Whether or not app is in AMP mode. @@ -106,10 +113,10 @@ declare module '$app/stores' { * A convenience function around `getContext` that returns `{ navigating, page, session }`. * Most of the time, you won't need to use it. */ - export function getStores(): { + export function getStores(): { navigating: typeof navigating; page: typeof page; - session: Writable; + session: Writable; updated: typeof updated; }; /** @@ -132,7 +139,7 @@ declare module '$app/stores' { * A writable store whose initial value is whatever was returned from `getSession`. * It can be written to, but this will not cause changes to persist on the server — this is something you must implement yourself. */ - export const session: Writable; + export const session: Writable; /** * A writable store indicating if the site was updated since the store was created. * It can be written to when custom logic is required to detect updates. diff --git a/packages/kit/types/helper.d.ts b/packages/kit/types/helper.d.ts index 3e85e1bf187c..f48f72b57491 100644 --- a/packages/kit/types/helper.d.ts +++ b/packages/kit/types/helper.d.ts @@ -16,9 +16,6 @@ export type ResponseHeaders = Record; type Only = { [P in keyof T]: T[P] } & { [P in Exclude]?: never }; export type Either = Only | Only; -export type InferValue = T extends Record - ? Val - : Default; export type MaybePromise = T | Promise; export type RecursiveRequired = { // Recursive implementation of TypeScript's Required utility type. diff --git a/packages/kit/types/page.d.ts b/packages/kit/types/page.d.ts index 5e143862cf33..0b274b28132f 100644 --- a/packages/kit/types/page.d.ts +++ b/packages/kit/types/page.d.ts @@ -1,85 +1,40 @@ import { Fallthrough } from './endpoint'; -import { Either, InferValue, MaybePromise } from './helper'; +import { Either, MaybePromise } from './helper'; -export interface LoadInput< - PageParams extends Record = Record, - Stuff extends Record = Record, - Session = any -> { +export interface LoadInput> { url: URL; - params: PageParams; + params: Params; fetch(info: RequestInfo, init?: RequestInit): Promise; - session: Session; - stuff: Stuff; + session: SvelteKit.Session; + stuff: Partial; } -export interface ErrorLoadInput< - PageParams extends Record = Record, - Stuff extends Record = Record, - Session = any -> extends LoadInput { +export interface ErrorLoadInput> extends LoadInput { status?: number; error?: Error; } -export interface LoadOutput< - Props extends Record = Record, - Stuff extends Record = Record -> { +export interface LoadOutput> { status?: number; error?: string | Error; redirect?: string; props?: Props; - stuff?: Stuff; + stuff?: Partial; maxage?: number; } interface LoadInputExtends { - stuff?: Record; - pageParams?: Record; - session?: any; + params?: Record; } interface LoadOutputExtends { - stuff?: Record; props?: Record; } -export interface Load< - Input extends LoadInputExtends = Required, - Output extends LoadOutputExtends = Required -> { - ( - input: LoadInput< - InferValue>, - InferValue>, - InferValue - > - ): MaybePromise< - Either< - Fallthrough, - LoadOutput< - InferValue>, - InferValue> - > - > - >; +export interface Load, Props = Record> { + (input: LoadInput): MaybePromise>>; } -export interface ErrorLoad< - Input extends LoadInputExtends = Required, - Output extends LoadOutputExtends = Required -> { - ( - input: ErrorLoadInput< - InferValue>, - InferValue>, - InferValue - > - ): MaybePromise< - LoadOutput< - InferValue>, - InferValue> - > - >; +export interface ErrorLoad, Props = Record> { + (input: ErrorLoadInput): MaybePromise>; } From de2157c4259db0285d32120e6345256cdc05af67 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:07:53 -0500 Subject: [PATCH 02/14] update templates --- .../templates/default/src/app.d.ts | 13 ++++++++++ .../templates/default/src/global.d.ts | 1 - .../templates/default/src/lib/types.d.ts | 7 ------ .../default/src/routes/todos/[uid].json.ts | 5 ++-- .../default/src/routes/todos/index.json.ts | 5 ++-- .../templates/skeleton/src/app.d.ts | 11 +++++++++ .../templates/skeleton/src/global.d.ts | 1 - packages/kit/types/endpoint.d.ts | 10 ++------ packages/kit/types/hooks.d.ts | 24 ++++++++----------- 9 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 packages/create-svelte/templates/default/src/app.d.ts delete mode 100644 packages/create-svelte/templates/default/src/global.d.ts delete mode 100644 packages/create-svelte/templates/default/src/lib/types.d.ts create mode 100644 packages/create-svelte/templates/skeleton/src/app.d.ts delete mode 100644 packages/create-svelte/templates/skeleton/src/global.d.ts diff --git a/packages/create-svelte/templates/default/src/app.d.ts b/packages/create-svelte/templates/default/src/app.d.ts new file mode 100644 index 000000000000..cc6b7a79acf1 --- /dev/null +++ b/packages/create-svelte/templates/default/src/app.d.ts @@ -0,0 +1,13 @@ +/// + +declare namespace SvelteKit { + interface Locals { + userid: string; + } + + interface Platform {} + + interface Session {} + + interface Stuff {} +} diff --git a/packages/create-svelte/templates/default/src/global.d.ts b/packages/create-svelte/templates/default/src/global.d.ts deleted file mode 100644 index 63908c66cfd4..000000000000 --- a/packages/create-svelte/templates/default/src/global.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/create-svelte/templates/default/src/lib/types.d.ts b/packages/create-svelte/templates/default/src/lib/types.d.ts deleted file mode 100644 index 6edddd1d6fb6..000000000000 --- a/packages/create-svelte/templates/default/src/lib/types.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Can be made globally available by placing this - * inside `global.d.ts` and removing `export` keyword - */ -export interface Locals { - userid: string; -} diff --git a/packages/create-svelte/templates/default/src/routes/todos/[uid].json.ts b/packages/create-svelte/templates/default/src/routes/todos/[uid].json.ts index 0ca276dbcbf3..e86c5f9bfeb8 100644 --- a/packages/create-svelte/templates/default/src/routes/todos/[uid].json.ts +++ b/packages/create-svelte/templates/default/src/routes/todos/[uid].json.ts @@ -1,9 +1,8 @@ import { api } from './_api'; import type { RequestHandler } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; // PATCH /todos/:uid.json -export const patch: RequestHandler = async (event) => { +export const patch: RequestHandler = async (event) => { const data = await event.request.formData(); return api(event, `todos/${event.locals.userid}/${event.params.uid}`, { @@ -13,6 +12,6 @@ export const patch: RequestHandler = async (event) => { }; // DELETE /todos/:uid.json -export const del: RequestHandler = async (event) => { +export const del: RequestHandler = async (event) => { return api(event, `todos/${event.locals.userid}/${event.params.uid}`); }; diff --git a/packages/create-svelte/templates/default/src/routes/todos/index.json.ts b/packages/create-svelte/templates/default/src/routes/todos/index.json.ts index c300fd971491..1edb0058a9cc 100644 --- a/packages/create-svelte/templates/default/src/routes/todos/index.json.ts +++ b/packages/create-svelte/templates/default/src/routes/todos/index.json.ts @@ -1,9 +1,8 @@ import { api } from './_api'; import type { RequestHandler } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; // GET /todos.json -export const get: RequestHandler = async (event) => { +export const get: RequestHandler = async (event) => { // event.locals.userid comes from src/hooks.js const response = await api(event, `todos/${event.locals.userid}`); @@ -17,7 +16,7 @@ export const get: RequestHandler = async (event) => { }; // POST /todos.json -export const post: RequestHandler = async (event) => { +export const post: RequestHandler = async (event) => { const data = await event.request.formData(); const response = await api(event, `todos/${event.locals.userid}`, { diff --git a/packages/create-svelte/templates/skeleton/src/app.d.ts b/packages/create-svelte/templates/skeleton/src/app.d.ts new file mode 100644 index 000000000000..3267ef7c46f6 --- /dev/null +++ b/packages/create-svelte/templates/skeleton/src/app.d.ts @@ -0,0 +1,11 @@ +/// + +declare namespace SvelteKit { + interface Locals {} + + interface Platform {} + + interface Session {} + + interface Stuff {} +} diff --git a/packages/create-svelte/templates/skeleton/src/global.d.ts b/packages/create-svelte/templates/skeleton/src/global.d.ts deleted file mode 100644 index 63908c66cfd4..000000000000 --- a/packages/create-svelte/templates/skeleton/src/global.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/kit/types/endpoint.d.ts b/packages/kit/types/endpoint.d.ts index d48099433d00..d60f39b8a7db 100644 --- a/packages/kit/types/endpoint.d.ts +++ b/packages/kit/types/endpoint.d.ts @@ -13,12 +13,6 @@ export interface Fallthrough { fallthrough: true; } -export interface RequestHandler< - Locals = Record, - Platform = Record, - Output extends Body = Body -> { - (event: RequestEvent): MaybePromise< - Either, Fallthrough> - >; +export interface RequestHandler { + (event: RequestEvent): MaybePromise, Fallthrough>>; } diff --git a/packages/kit/types/hooks.d.ts b/packages/kit/types/hooks.d.ts index afaca61969c3..b1682ee31b45 100644 --- a/packages/kit/types/hooks.d.ts +++ b/packages/kit/types/hooks.d.ts @@ -2,35 +2,31 @@ import { MaybePromise } from './helper'; export type StrictBody = string | Uint8Array; -export interface RequestEvent, Platform = Record> { +export interface RequestEvent { request: Request; url: URL; params: Record; - locals: Locals; - platform: Readonly; + locals: SvelteKit.Locals; + platform: Readonly; } -export interface GetSession< - Locals = Record, - Platform = Record, - Session = any -> { - (event: RequestEvent): MaybePromise; +export interface GetSession { + (event: RequestEvent): MaybePromise; } export interface ResolveOpts { ssr?: boolean; } -export interface Handle, Platform = Record> { +export interface Handle { (input: { - event: RequestEvent; - resolve(event: RequestEvent, opts?: ResolveOpts): MaybePromise; + event: RequestEvent; + resolve(event: RequestEvent, opts?: ResolveOpts): MaybePromise; }): MaybePromise; } -export interface HandleError> { - (input: { error: Error & { frame?: string }; event: RequestEvent }): void; +export interface HandleError { + (input: { error: Error & { frame?: string }; event: RequestEvent }): void; } export interface ExternalFetch { From 901a25d54e45fcbb7eb99454399943e7a0b703ae Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:14:09 -0500 Subject: [PATCH 03/14] update docs --- documentation/docs/01-routing.md | 16 ++++------- documentation/docs/02-layouts.md | 7 ++--- documentation/docs/03-loading.md | 49 ++++++-------------------------- documentation/docs/04-hooks.md | 26 +++++++---------- packages/kit/types/page.d.ts | 8 ------ 5 files changed, 26 insertions(+), 80 deletions(-) diff --git a/documentation/docs/01-routing.md b/documentation/docs/01-routing.md index 8af291a249b8..bd18a06f81b4 100644 --- a/documentation/docs/01-routing.md +++ b/documentation/docs/01-routing.md @@ -51,12 +51,12 @@ Endpoints are modules written in `.js` (or `.ts`) files that export functions co // Declaration types for Endpoints // * declarations that are not exported are for internal use -export interface RequestEvent, Platform = Record> { +export interface RequestEvent { request: Request; url: URL; params: Record; - locals: Locals; - platform: Platform; + locals: SvelteKit.Locals; + platform: SvelteKit.Platform; } type Body = JSONString | Uint8Array | ReadableStream | stream.Readable; @@ -71,14 +71,8 @@ interface Fallthrough { fallthrough: true; } -export interface RequestHandler< - Locals = Record, - Platform = Record, - Output extends Body = Body -> { - (event: RequestEvent): MaybePromise< - Either, Fallthrough> - >; +export interface RequestHandler { + (event: RequestEvent): MaybePromise, Fallthrough>>; } ``` diff --git a/documentation/docs/02-layouts.md b/documentation/docs/02-layouts.md index 6211e825b3d1..9174dc651a9b 100644 --- a/documentation/docs/02-layouts.md +++ b/documentation/docs/02-layouts.md @@ -80,11 +80,8 @@ For example, if `src/routes/settings/notifications/index.svelte` failed to load, // declaration type // * also see type for `LoadOutput` in the Loading section -export interface ErrorLoadInput< - PageParams extends Record = Record, - Stuff extends Record = Record, - Session = any -> extends LoadInput { +export interface ErrorLoadInput = Record> + extends LoadInput { status?: number; error?: Error; } diff --git a/documentation/docs/03-loading.md b/documentation/docs/03-loading.md index 51d91571432b..e50f7a3ae077 100644 --- a/documentation/docs/03-loading.md +++ b/documentation/docs/03-loading.md @@ -8,63 +8,30 @@ A component that defines a page or a layout can export a `load` function that ru // Declaration types for Loading // * declarations that are not exported are for internal use -export interface LoadInput< - PageParams extends Record = Record, - Stuff extends Record = Record, - Session = any -> { +export interface LoadInput = Record> { url: URL; params: PageParams; fetch(info: RequestInfo, init?: RequestInit): Promise; - session: Session; - stuff: Stuff; + session: SvelteKit.Session; + stuff: Partial; } -export interface LoadOutput< - Props extends Record = Record, - Stuff extends Record = Record -> { +export interface LoadOutput = Record> { status?: number; error?: string | Error; redirect?: string; props?: Props; - stuff?: Stuff; + stuff?: Partial; maxage?: number; } -interface LoadInputExtends { - stuff?: Record; - pageParams?: Record; - session?: any; -} -interface LoadOutputExtends { - stuff?: Record; - props?: Record; -} - type MaybePromise = T | Promise; interface Fallthrough { fallthrough: true; } -export interface Load< - Input extends LoadInputExtends = Required, - Output extends LoadOutputExtends = Required -> { - ( - input: LoadInput< - InferValue>, - InferValue>, - InferValue - > - ): MaybePromise< - Either< - Fallthrough, - LoadOutput< - InferValue>, - InferValue> - > - > - >; + +export interface Load, Props = Record> { + (input: LoadInput): MaybePromise>>; } ``` diff --git a/documentation/docs/04-hooks.md b/documentation/docs/04-hooks.md index f3378de7d5fc..1cca31485a31 100644 --- a/documentation/docs/04-hooks.md +++ b/documentation/docs/04-hooks.md @@ -22,22 +22,22 @@ If unimplemented, defaults to `({ event, resolve }) => resolve(event)`. // everything else must be a type of string type ResponseHeaders = Record; -export interface RequestEvent, Platform = Record> { +export interface RequestEvent { request: Request; url: URL; params: Record; - locals: Locals; - platform: Platform; + locals: SvelteKit.Locals; + platform: SvelteKit.Platform; } export interface ResolveOpts { ssr?: boolean; } -export interface Handle, Platform = Record> { +export interface Handle { (input: { - event: RequestEvent; - resolve(event: RequestEvent, opts?: ResolveOpts): MaybePromise; + event: RequestEvent; + resolve(event: RequestEvent, opts?: ResolveOpts): MaybePromise; }): MaybePromise; } ``` @@ -85,8 +85,8 @@ If unimplemented, SvelteKit will log the error with default formatting. ```ts // Declaration types for handleError hook -export interface HandleError, Platform = Record> { - (input: { error: Error & { frame?: string }; event: RequestEvent }): void; +export interface HandleError { + (input: { error: Error & { frame?: string }; event: RequestEvent }): void; } ``` @@ -108,12 +108,8 @@ If unimplemented, session is `{}`. ```ts // Declaration types for getSession hook -export interface GetSession< - Locals = Record, - Platform = Record, - Session = any -> { - (event: RequestEvent): MaybePromise; +export interface GetSession { + (event: RequestEvent): MaybePromise; } ``` @@ -130,7 +126,7 @@ export function getSession(event) { email: event.locals.user.email, avatar: event.locals.user.avatar } - } + } : {}; } ``` diff --git a/packages/kit/types/page.d.ts b/packages/kit/types/page.d.ts index 0b274b28132f..d0b5b06db5a3 100644 --- a/packages/kit/types/page.d.ts +++ b/packages/kit/types/page.d.ts @@ -23,14 +23,6 @@ export interface LoadOutput> { maxage?: number; } -interface LoadInputExtends { - params?: Record; -} - -interface LoadOutputExtends { - props?: Record; -} - export interface Load, Props = Record> { (input: LoadInput): MaybePromise>>; } From d5292311e4f611fae867bcd5540486121ae78c84 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:19:37 -0500 Subject: [PATCH 04/14] fix some test types --- packages/kit/test/apps/basics/src/app.d.ts | 7 +++++++ packages/kit/test/apps/basics/src/hooks.js | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/kit/test/apps/basics/src/app.d.ts b/packages/kit/test/apps/basics/src/app.d.ts index 06aacd5e3b51..a5da601c6cfc 100644 --- a/packages/kit/test/apps/basics/src/app.d.ts +++ b/packages/kit/test/apps/basics/src/app.d.ts @@ -1,4 +1,11 @@ declare namespace SvelteKit { + interface Locals { + answer: number; + name: string; + } + + interface Platform {} + interface Session { answer: number; calls: number; diff --git a/packages/kit/test/apps/basics/src/hooks.js b/packages/kit/test/apps/basics/src/hooks.js index dec1a29338cb..dfb9959d0e66 100644 --- a/packages/kit/test/apps/basics/src/hooks.js +++ b/packages/kit/test/apps/basics/src/hooks.js @@ -4,7 +4,10 @@ import { sequence } from '../../../../src/hooks'; /** @type {import('@sveltejs/kit').GetSession} */ export function getSession(request) { - return request.locals; + return { + answer: request.locals.answer, + calls: 0 + }; } /** @type {import('@sveltejs/kit').HandleError} */ From 18f0c3099b0741a4ff96c9e9b4e1a1c4f68523dd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:29:33 -0500 Subject: [PATCH 05/14] get typechecking to pass --- packages/kit/src/core/dev/plugin.js | 1 + packages/kit/src/runtime/server/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/kit/src/core/dev/plugin.js b/packages/kit/src/core/dev/plugin.js index a35314d02f17..8a676a9c3371 100644 --- a/packages/kit/src/core/dev/plugin.js +++ b/packages/kit/src/core/dev/plugin.js @@ -175,6 +175,7 @@ export async function create_plugin(config, cwd) { /** @type {import('types/internal').Hooks} */ const hooks = { + // @ts-expect-error this picks up types that belong to the tests getSession: user_hooks.getSession || (() => ({})), handle: amp ? sequence(amp, handle) : handle, handleError: diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 3f1edbd16583..d5b56d2a009a 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -60,6 +60,7 @@ export async function respond(request, options, state = {}) { request, url, params: {}, + // @ts-expect-error this picks up types that belong to the tests locals: {}, platform: state.platform }; From 1040e967a4d1ef156718f866646e0e114b869f59 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:47:10 -0500 Subject: [PATCH 06/14] document app-level types --- documentation/docs/15-typescript.md | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 documentation/docs/15-typescript.md diff --git a/documentation/docs/15-typescript.md b/documentation/docs/15-typescript.md new file mode 100644 index 000000000000..6d39fd841f38 --- /dev/null +++ b/documentation/docs/15-typescript.md @@ -0,0 +1,37 @@ +--- +title: TypeScript +--- + +All APIs in SvelteKit are fully typed. Additionally, it's possible to tell SvelteKit how to type objects inside your app by declaring the `SvelteKit` namespace. By default, a new project will have a file called `src/app.d.ts` containing the following: + +```ts +/// + +declare namespace SvelteKit { + interface Locals {} + + interface Platform {} + + interface Session {} + + interface Stuff {} +} +``` + +By populating these interfaces, you will gain type safety when using `event.locals`, `event.platform`, `session` and `stuff`: + +### SvelteKit.Locals + +The interface that defines `event.locals`, which can be accessed in [hooks](#hooks) (`handle`, `handleError` and `getSession`) and [endpoints](#endpoints). + +### SvelteKit.Platform + +If your adapter provides [platform-specific context](#adapters-supported-environments-platform-specific-context) via `event.platform`, you can specify it here. + +### SvelteKit.Session + +The interface that defines `session`, both as an argument to [`load`](#loading) functions and the value of the [session store](#modules-$app-stores). + +### SvelteKit.Stuff + +The interface that defines `stuff`, as input or output to [`load`](#loading) or as the value of the `stuff` property of the [page store](#modules-$app-stores). From 2e85e1ee88b8c3ab837cf39abd6834bb337242ed Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:48:16 -0500 Subject: [PATCH 07/14] changeset --- .changeset/ninety-suns-relax.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/ninety-suns-relax.md diff --git a/.changeset/ninety-suns-relax.md b/.changeset/ninety-suns-relax.md new file mode 100644 index 000000000000..5a70cc6a2822 --- /dev/null +++ b/.changeset/ninety-suns-relax.md @@ -0,0 +1,6 @@ +--- +'create-svelte': patch +'@sveltejs/kit': patch +--- + +Add SvelteKit namespace for app-level types From c57837f57fb3a18a7839f7c5bd937e604ef68926 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:52:33 -0500 Subject: [PATCH 08/14] link to typescript section --- documentation/docs/01-routing.md | 2 ++ documentation/docs/03-loading.md | 4 +++- documentation/docs/04-hooks.md | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/documentation/docs/01-routing.md b/documentation/docs/01-routing.md index bd18a06f81b4..437c9e35023c 100644 --- a/documentation/docs/01-routing.md +++ b/documentation/docs/01-routing.md @@ -76,6 +76,8 @@ export interface RequestHandler { } ``` +> See the [TypeScript](#typescript) section for information on `SvelteKit.Locals` and `SvelteKit.Platform`. + For example, our hypothetical blog page, `/blog/cool-article`, might request data from `/blog/cool-article.json`, which could be represented by a `src/routes/blog/[slug].json.js` endpoint: ```js diff --git a/documentation/docs/03-loading.md b/documentation/docs/03-loading.md index e50f7a3ae077..257ab835181c 100644 --- a/documentation/docs/03-loading.md +++ b/documentation/docs/03-loading.md @@ -10,7 +10,7 @@ A component that defines a page or a layout can export a `load` function that ru export interface LoadInput = Record> { url: URL; - params: PageParams; + params: Params; fetch(info: RequestInfo, init?: RequestInit): Promise; session: SvelteKit.Session; stuff: Partial; @@ -35,6 +35,8 @@ export interface Load, Props = Record See the [TypeScript](#typescript) section for information on `SvelteKit.Session` and `SvelteKit.Stuff`. + Our example blog page might contain a `load` function like the following: ```html diff --git a/documentation/docs/04-hooks.md b/documentation/docs/04-hooks.md index 1cca31485a31..4d9503980462 100644 --- a/documentation/docs/04-hooks.md +++ b/documentation/docs/04-hooks.md @@ -42,6 +42,8 @@ export interface Handle { } ``` +> See the [TypeScript](#typescript) section for information on `SvelteKit.Locals` and `SvelteKit.Platform`. + To add custom data to the request, which is passed to endpoints, populate the `event.locals` object, as shown below. ```js From 1f9feec532c6eac7a6853cbf4f99abcf742b8dc0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:54:15 -0500 Subject: [PATCH 09/14] rename namespace to App --- documentation/docs/01-routing.md | 6 +++--- documentation/docs/03-loading.md | 8 ++++---- documentation/docs/04-hooks.md | 8 ++++---- documentation/docs/15-typescript.md | 12 ++++++------ .../create-svelte/templates/default/src/app.d.ts | 2 +- .../create-svelte/templates/skeleton/src/app.d.ts | 2 +- packages/kit/test/apps/basics/src/app.d.ts | 2 +- packages/kit/types/ambient-modules.d.ts | 6 +++--- packages/kit/types/hooks.d.ts | 6 +++--- packages/kit/types/page.d.ts | 6 +++--- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/documentation/docs/01-routing.md b/documentation/docs/01-routing.md index 437c9e35023c..8dc0e1364c9b 100644 --- a/documentation/docs/01-routing.md +++ b/documentation/docs/01-routing.md @@ -55,8 +55,8 @@ export interface RequestEvent { request: Request; url: URL; params: Record; - locals: SvelteKit.Locals; - platform: SvelteKit.Platform; + locals: App.Locals; + platform: App.Platform; } type Body = JSONString | Uint8Array | ReadableStream | stream.Readable; @@ -76,7 +76,7 @@ export interface RequestHandler { } ``` -> See the [TypeScript](#typescript) section for information on `SvelteKit.Locals` and `SvelteKit.Platform`. +> See the [TypeScript](#typescript) section for information on `App.Locals` and `App.Platform`. For example, our hypothetical blog page, `/blog/cool-article`, might request data from `/blog/cool-article.json`, which could be represented by a `src/routes/blog/[slug].json.js` endpoint: diff --git a/documentation/docs/03-loading.md b/documentation/docs/03-loading.md index 257ab835181c..1caa408b67ba 100644 --- a/documentation/docs/03-loading.md +++ b/documentation/docs/03-loading.md @@ -12,8 +12,8 @@ export interface LoadInput = Record; - session: SvelteKit.Session; - stuff: Partial; + session: App.Session; + stuff: Partial; } export interface LoadOutput = Record> { @@ -21,7 +21,7 @@ export interface LoadOutput = Record; + stuff?: Partial; maxage?: number; } @@ -35,7 +35,7 @@ export interface Load, Props = Record See the [TypeScript](#typescript) section for information on `SvelteKit.Session` and `SvelteKit.Stuff`. +> See the [TypeScript](#typescript) section for information on `App.Session` and `App.Stuff`. Our example blog page might contain a `load` function like the following: diff --git a/documentation/docs/04-hooks.md b/documentation/docs/04-hooks.md index 4d9503980462..c873dd535bb6 100644 --- a/documentation/docs/04-hooks.md +++ b/documentation/docs/04-hooks.md @@ -26,8 +26,8 @@ export interface RequestEvent { request: Request; url: URL; params: Record; - locals: SvelteKit.Locals; - platform: SvelteKit.Platform; + locals: App.Locals; + platform: App.Platform; } export interface ResolveOpts { @@ -42,7 +42,7 @@ export interface Handle { } ``` -> See the [TypeScript](#typescript) section for information on `SvelteKit.Locals` and `SvelteKit.Platform`. +> See the [TypeScript](#typescript) section for information on `App.Locals` and `App.Platform`. To add custom data to the request, which is passed to endpoints, populate the `event.locals` object, as shown below. @@ -111,7 +111,7 @@ If unimplemented, session is `{}`. ```ts // Declaration types for getSession hook export interface GetSession { - (event: RequestEvent): MaybePromise; + (event: RequestEvent): MaybePromise; } ``` diff --git a/documentation/docs/15-typescript.md b/documentation/docs/15-typescript.md index 6d39fd841f38..7722933b0f06 100644 --- a/documentation/docs/15-typescript.md +++ b/documentation/docs/15-typescript.md @@ -2,12 +2,12 @@ title: TypeScript --- -All APIs in SvelteKit are fully typed. Additionally, it's possible to tell SvelteKit how to type objects inside your app by declaring the `SvelteKit` namespace. By default, a new project will have a file called `src/app.d.ts` containing the following: +All APIs in SvelteKit are fully typed. Additionally, 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: ```ts /// -declare namespace SvelteKit { +declare namespace App { interface Locals {} interface Platform {} @@ -20,18 +20,18 @@ declare namespace SvelteKit { By populating these interfaces, you will gain type safety when using `event.locals`, `event.platform`, `session` and `stuff`: -### SvelteKit.Locals +### App.Locals The interface that defines `event.locals`, which can be accessed in [hooks](#hooks) (`handle`, `handleError` and `getSession`) and [endpoints](#endpoints). -### SvelteKit.Platform +### App.Platform If your adapter provides [platform-specific context](#adapters-supported-environments-platform-specific-context) via `event.platform`, you can specify it here. -### SvelteKit.Session +### App.Session The interface that defines `session`, both as an argument to [`load`](#loading) functions and the value of the [session store](#modules-$app-stores). -### SvelteKit.Stuff +### App.Stuff The interface that defines `stuff`, as input or output to [`load`](#loading) or as the value of the `stuff` property of the [page store](#modules-$app-stores). diff --git a/packages/create-svelte/templates/default/src/app.d.ts b/packages/create-svelte/templates/default/src/app.d.ts index cc6b7a79acf1..88b646f6d8bb 100644 --- a/packages/create-svelte/templates/default/src/app.d.ts +++ b/packages/create-svelte/templates/default/src/app.d.ts @@ -1,6 +1,6 @@ /// -declare namespace SvelteKit { +declare namespace App { interface Locals { userid: string; } diff --git a/packages/create-svelte/templates/skeleton/src/app.d.ts b/packages/create-svelte/templates/skeleton/src/app.d.ts index 3267ef7c46f6..d8c081b14d05 100644 --- a/packages/create-svelte/templates/skeleton/src/app.d.ts +++ b/packages/create-svelte/templates/skeleton/src/app.d.ts @@ -1,6 +1,6 @@ /// -declare namespace SvelteKit { +declare namespace App { interface Locals {} interface Platform {} diff --git a/packages/kit/test/apps/basics/src/app.d.ts b/packages/kit/test/apps/basics/src/app.d.ts index a5da601c6cfc..eada2bd808ce 100644 --- a/packages/kit/test/apps/basics/src/app.d.ts +++ b/packages/kit/test/apps/basics/src/app.d.ts @@ -1,4 +1,4 @@ -declare namespace SvelteKit { +declare namespace App { interface Locals { answer: number; name: string; diff --git a/packages/kit/types/ambient-modules.d.ts b/packages/kit/types/ambient-modules.d.ts index 969c4364b540..8d9643120711 100644 --- a/packages/kit/types/ambient-modules.d.ts +++ b/packages/kit/types/ambient-modules.d.ts @@ -1,6 +1,6 @@ /* eslint-disable import/no-duplicates */ -declare namespace SvelteKit { +declare namespace App { interface Locals {} interface Platform {} interface Session {} @@ -116,7 +116,7 @@ declare module '$app/stores' { export function getStores(): { navigating: typeof navigating; page: typeof page; - session: Writable; + session: Writable; updated: typeof updated; }; /** @@ -139,7 +139,7 @@ declare module '$app/stores' { * A writable store whose initial value is whatever was returned from `getSession`. * It can be written to, but this will not cause changes to persist on the server — this is something you must implement yourself. */ - export const session: Writable; + export const session: Writable; /** * A writable store indicating if the site was updated since the store was created. * It can be written to when custom logic is required to detect updates. diff --git a/packages/kit/types/hooks.d.ts b/packages/kit/types/hooks.d.ts index b1682ee31b45..fdcf697bdfa2 100644 --- a/packages/kit/types/hooks.d.ts +++ b/packages/kit/types/hooks.d.ts @@ -6,12 +6,12 @@ export interface RequestEvent { request: Request; url: URL; params: Record; - locals: SvelteKit.Locals; - platform: Readonly; + locals: App.Locals; + platform: Readonly; } export interface GetSession { - (event: RequestEvent): MaybePromise; + (event: RequestEvent): MaybePromise; } export interface ResolveOpts { diff --git a/packages/kit/types/page.d.ts b/packages/kit/types/page.d.ts index d0b5b06db5a3..8aff51ce9183 100644 --- a/packages/kit/types/page.d.ts +++ b/packages/kit/types/page.d.ts @@ -5,8 +5,8 @@ export interface LoadInput> { url: URL; params: Params; fetch(info: RequestInfo, init?: RequestInit): Promise; - session: SvelteKit.Session; - stuff: Partial; + session: App.Session; + stuff: Partial; } export interface ErrorLoadInput> extends LoadInput { @@ -19,7 +19,7 @@ export interface LoadOutput> { error?: string | Error; redirect?: string; props?: Props; - stuff?: Partial; + stuff?: Partial; maxage?: number; } From 6b14d3092fbe5c077cc5949a0d39708b9c7521a0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 17:54:36 -0500 Subject: [PATCH 10/14] update changeset --- .changeset/ninety-suns-relax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ninety-suns-relax.md b/.changeset/ninety-suns-relax.md index 5a70cc6a2822..29dd3e693b5c 100644 --- a/.changeset/ninety-suns-relax.md +++ b/.changeset/ninety-suns-relax.md @@ -3,4 +3,4 @@ '@sveltejs/kit': patch --- -Add SvelteKit namespace for app-level types +Add App namespace for app-level types From a091afa4ec92be69be6b5bb3c7b9f71752d023cf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Feb 2022 18:07:00 -0500 Subject: [PATCH 11/14] shut up eslint no-one likes you --- packages/kit/.eslintrc.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kit/.eslintrc.json b/packages/kit/.eslintrc.json index c8debbb5c06e..bca2ace00477 100644 --- a/packages/kit/.eslintrc.json +++ b/packages/kit/.eslintrc.json @@ -11,5 +11,8 @@ "prefetchRoutes": true, "beforeNavigate": true, "afterNavigate": true + }, + "rules": { + "@typescript-eslint/no-empty-interface": "off" } } From 10406eba8fa7e061e77b36c4a38be7ed5307ed6c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Feb 2022 09:14:10 -0500 Subject: [PATCH 12/14] point to docs --- packages/create-svelte/templates/default/src/app.d.ts | 2 ++ packages/create-svelte/templates/skeleton/src/app.d.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/create-svelte/templates/default/src/app.d.ts b/packages/create-svelte/templates/default/src/app.d.ts index 88b646f6d8bb..dd7d35856f42 100644 --- a/packages/create-svelte/templates/default/src/app.d.ts +++ b/packages/create-svelte/templates/default/src/app.d.ts @@ -1,5 +1,7 @@ /// +// See https://kit.svelte.dev/docs#typescript +// for information about these interfaces declare namespace App { interface Locals { userid: string; diff --git a/packages/create-svelte/templates/skeleton/src/app.d.ts b/packages/create-svelte/templates/skeleton/src/app.d.ts index d8c081b14d05..161703cac14d 100644 --- a/packages/create-svelte/templates/skeleton/src/app.d.ts +++ b/packages/create-svelte/templates/skeleton/src/app.d.ts @@ -1,5 +1,7 @@ /// +// See https://kit.svelte.dev/docs#typescript +// for information about these interfaces declare namespace App { interface Locals {} From d5e7d58597db40285a6424455640fa53cfb6ba86 Mon Sep 17 00:00:00 2001 From: Ignatius Bagus Date: Wed, 2 Feb 2022 21:57:39 +0700 Subject: [PATCH 13/14] remove Locals from todos/_api default template --- .../create-svelte/templates/default/src/routes/todos/_api.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/create-svelte/templates/default/src/routes/todos/_api.ts b/packages/create-svelte/templates/default/src/routes/todos/_api.ts index 4e13eb029573..97e8f790050d 100644 --- a/packages/create-svelte/templates/default/src/routes/todos/_api.ts +++ b/packages/create-svelte/templates/default/src/routes/todos/_api.ts @@ -1,5 +1,4 @@ import type { EndpointOutput, RequestEvent } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; /* This module is used by the /todos.json and /todos/[uid].json @@ -15,7 +14,7 @@ import type { Locals } from '$lib/types'; const base = 'https://api.svelte.dev'; export async function api( - event: RequestEvent, + event: RequestEvent, resource: string, data?: Record ): Promise { From 52b31ee99e06e94bfa1f7f15ff66162198acb106 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Feb 2022 10:26:37 -0500 Subject: [PATCH 14/14] update adapter-cloudflare docs --- packages/adapter-cloudflare/README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/adapter-cloudflare/README.md b/packages/adapter-cloudflare/README.md index dffc3709a003..9a52fc120c4b 100644 --- a/packages/adapter-cloudflare/README.md +++ b/packages/adapter-cloudflare/README.md @@ -56,16 +56,25 @@ When configuring your project settings, you must use the following settings: The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object, containing KV namespaces etc, is passed to SvelteKit via the `platform` property, meaning you can access it in hooks and endpoints: -```ts -interface Locals {} +```diff +// src/app.d.ts +declare namespace App { + interface Locals {} -interface Platform { - env: { - COUNTER: DurableObjectNamespace; - }; ++ interface Platform { ++ env: { ++ COUNTER: DurableObjectNamespace; ++ }; ++ } + + interface Session {} + + interface Stuff {} } +``` -export async function post({ request, platform }) { +```js +export async function post({ request, platform }) { const counter = platform.env.COUNTER.idFromName('A'); } ```