Skip to content

Commit ad0ffa2

Browse files
authored
[fix] Fix params and parent data types (#5974)
* Fix params and parent data types * add output generic to load function types, helps with #5963 * remove JSONObject, add event types to $types * fix types * changeset
1 parent 7b4803a commit ad0ffa2

File tree

13 files changed

+81
-70
lines changed

13 files changed

+81
-70
lines changed

.changeset/sour-cherries-play.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
Tighten up params typings, fix load function typings, add event typings to generated types

packages/kit/src/core/sync/write_types.js

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,18 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
246246

247247
exports.push(`export type PageData = ${data};`);
248248
if (load) {
249-
exports.push(`export type PageLoad = ${load};`);
249+
exports.push(
250+
`export type PageLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
251+
);
252+
exports.push('export type PageLoadEvent = Parameters<PageLoad>[0];');
250253
}
251254

252255
exports.push(`export type PageServerData = ${server_data};`);
253256
if (server_load) {
254-
exports.push(`export type PageServerLoad = ${server_load};`);
257+
exports.push(
258+
`export type PageServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
259+
);
260+
exports.push('export type PageServerLoadEvent = Parameters<PageServerLoad>[0];');
255261
}
256262

257263
if (group.leaf.server) {
@@ -292,12 +298,18 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
292298

293299
exports.push(`export type LayoutData = ${data};`);
294300
if (load) {
295-
exports.push(`export type LayoutLoad = ${load};`);
301+
exports.push(
302+
`export type LayoutLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
303+
);
304+
exports.push('export type LayoutLoadEvent = Parameters<LayoutLoad>[0];');
296305
}
297306

298307
exports.push(`export type LayoutServerData = ${server_data};`);
299308
if (server_load) {
300-
exports.push(`export type LayoutServerLoad = ${server_load};`);
309+
exports.push(
310+
`export type LayoutServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
311+
);
312+
exports.push('export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];');
301313
}
302314
}
303315

@@ -311,9 +323,15 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
311323
/** @type {string[]} */
312324
const load_exports = [];
313325

326+
/** @type {string[]} */
327+
const load_event_exports = [];
328+
314329
/** @type {string[]} */
315330
const server_load_exports = [];
316331

332+
/** @type {string[]} */
333+
const server_load_event_exports = [];
334+
317335
for (const [name, node] of group.named_layouts) {
318336
const { data, server_data, load, server_load, written_proxies } = process_node(
319337
ts,
@@ -326,26 +344,39 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
326344
data_exports.push(`export type ${name} = ${data};`);
327345
server_data_exports.push(`export type ${name} = ${server_data};`);
328346
if (load) {
329-
load_exports.push(`export type ${name} = ${load};`);
347+
load_exports.push(
348+
`export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
349+
);
350+
load_event_exports.push(`export type ${name} = Parameters<LayoutLoad.${name}>[0];`);
330351
}
331352
if (server_load) {
332-
server_load_exports.push(`export type ${name} = ${load};`);
353+
server_load_exports.push(
354+
`export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
355+
);
356+
server_load_event_exports.push(
357+
`export type ${name} = Parameters<LayoutServerLoad.${name}>[0];`
358+
);
333359
}
334360
}
335361

336362
exports.push(`\nexport namespace LayoutData {\n\t${data_exports.join('\n\t')}\n}`);
337363
exports.push(`\nexport namespace LayoutLoad {\n\t${load_exports.join('\n\t')}\n}`);
364+
exports.push(`\nexport namespace LayoutLoadEvent {\n\t${load_event_exports.join('\n\t')}\n}`);
338365
exports.push(
339366
`\nexport namespace LayoutServerData {\n\t${server_data_exports.join('\n\t')}\n}`
340367
);
341368
exports.push(
342369
`\nexport namespace LayoutServerLoad {\n\t${server_load_exports.join('\n\t')}\n}`
343370
);
371+
exports.push(
372+
`\nexport namespace LayoutServerLoadEvent {\n\t${server_load_event_exports.join('\n\t')}\n}`
373+
);
344374
}
345375
}
346376

347377
if (group.endpoint) {
348378
exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams>;`);
379+
exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams>;`);
349380
}
350381

351382
const output = [imports.join('\n'), declarations.join('\n'), exports.join('\n')]
@@ -384,7 +415,7 @@ function process_node(ts, node, outdir, params, groups) {
384415
}
385416

386417
server_data = get_data_type(node.server, 'load', 'null', proxy);
387-
server_load = `Kit.ServerLoad<${params}, ${get_parent_type('LayoutServerData')}>`;
418+
server_load = `Kit.ServerLoad<${params}, ${get_parent_type('LayoutServerData')}, OutputData>`;
388419

389420
if (proxy) {
390421
const types = [];
@@ -415,7 +446,7 @@ function process_node(ts, node, outdir, params, groups) {
415446
}
416447

417448
data = get_data_type(node.shared, 'load', server_data, proxy);
418-
load = `Kit.Load<${params}, ${server_data}, ${get_parent_type('LayoutData')}>`;
449+
load = `Kit.Load<${params}, ${server_data}, ${get_parent_type('LayoutData')}, OutputData>`;
419450
} else {
420451
data = server_data;
421452
}
@@ -468,7 +499,7 @@ function process_node(ts, node, outdir, params, groups) {
468499
parent = parent_layout.parent;
469500
}
470501

471-
let parent_str = parent_imports[0] || 'null';
502+
let parent_str = parent_imports[0] || 'Record<never, never>';
472503
for (let i = 1; i < parent_imports.length; i++) {
473504
// Omit is necessary because a parent could have a property with the same key which would
474505
// cause a type conflict. At runtime the child overwrites the parent property in this case,

packages/kit/src/runtime/client/client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ export function create_client({ target, base, trailing_slash }) {
448448
* url: URL;
449449
* params: Record<string, string>;
450450
* routeId: string | null;
451-
* server_data: import('types').JSONObject | null;
451+
* server_data: Record<string, any> | null;
452452
* }} options
453453
* @returns {Promise<import('./types').BranchNode>}
454454
*/

packages/kit/src/runtime/client/types.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
prefetch,
77
prefetchRoutes
88
} from '$app/navigation';
9-
import { CSRPageNode, CSRRoute, JSONObject } from 'types';
9+
import { CSRPageNode, CSRRoute } from 'types';
1010
import { HttpError } from '../../index/private.js';
1111
import { SerializedHttpError } from '../server/page/types.js';
1212

@@ -92,7 +92,7 @@ export interface ServerDataRedirected {
9292
export interface ServerDataLoaded {
9393
type: 'data';
9494
nodes: Array<{
95-
data?: JSONObject | null; // TODO or `-1` to indicate 'reuse cached data'?
95+
data?: Record<string, any> | null; // TODO or `-1` to indicate 'reuse cached data'?
9696
status?: number;
9797
message?: string;
9898
error?: {

packages/kit/src/runtime/server/endpoint.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export async function render_endpoint(event, route) {
2929
return method_not_allowed(mod, method);
3030
}
3131

32-
const response = await handler(event);
32+
const response = await handler(
33+
/** @type {import('types').RequestEvent<Record<string, any>>} */ (event)
34+
);
3335

3436
if (!(response instanceof Response)) {
3537
return new Response(

packages/kit/src/runtime/server/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export async function respond(request, options, state) {
257257
event,
258258
node,
259259
parent: async () => {
260-
/** @type {import('types').JSONObject} */
260+
/** @type {Record<string, any>} */
261261
const data = {};
262262
for (let j = 0; j < i; j += 1) {
263263
const parent = await promises[j];

packages/kit/src/runtime/server/page/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export async function render_page(event, route, options, state, resolve_opts) {
137137
/** @type {Error | null} */
138138
let load_error = null;
139139

140-
/** @type {Array<Promise<import('types').JSONObject | null>>} */
140+
/** @type {Array<Promise<Record<string, any> | null>>} */
141141
const server_promises = nodes.map((node, i) => {
142142
if (load_error) {
143143
// if an error happens immediately, don't bother with the rest of the nodes
@@ -156,7 +156,7 @@ export async function render_page(event, route, options, state, resolve_opts) {
156156
event,
157157
node,
158158
parent: async () => {
159-
/** @type {import('types').JSONObject} */
159+
/** @type {Record<string, any>} */
160160
const data = {};
161161
for (let j = 0; j < i; j += 1) {
162162
Object.assign(data, await server_promises[j]);

packages/kit/src/runtime/server/page/load_data.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { LoadURL, PrerenderingURL } from '../../../utils/url.js';
55
* @param {{
66
* event: import('types').RequestEvent;
77
* node: import('types').SSRNode | undefined;
8-
* parent: () => Promise<import('types').JSONObject | null>;
8+
* parent: () => Promise<Record<string, any>>;
99
* }} opts
1010
*/
1111
export async function load_server_data({ event, node, parent }) {
@@ -37,7 +37,7 @@ export async function load_server_data({ event, node, parent }) {
3737
* fetcher: typeof fetch;
3838
* node: import('types').SSRNode | undefined;
3939
* parent: () => Promise<Record<string, any>>;
40-
* server_data_promise: Promise<import('types').JSONObject | null>;
40+
* server_data_promise: Promise<Record<string, any> | null>;
4141
* state: import('types').SSRState;
4242
* }} opts
4343
*/
@@ -70,7 +70,7 @@ export async function load_data({ event, fetcher, node, parent, server_data_prom
7070

7171
/** @param {Record<string, any>} object */
7272
async function unwrap_promises(object) {
73-
/** @type {import('types').JSONObject} */
73+
/** @type {Record<string, any>} */
7474
const unwrapped = {};
7575

7676
for (const key in object) {

packages/kit/src/runtime/server/page/render.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export async function render_response({
8686
/** @type {import('types').Page} */
8787
page: {
8888
error,
89-
params: event.params,
89+
params: /** @type {Record<string, any>} */ (event.params),
9090
routeId: event.routeId,
9191
status,
9292
url: state.prerendering ? new PrerenderingURL(event.url) : event.url,

packages/kit/src/runtime/server/page/types.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { JSONValue, ResponseHeaders, SSRNode, CspDirectives } from 'types';
1+
import { ResponseHeaders, SSRNode, CspDirectives } from 'types';
22
import { HttpError } from '../../../index/private';
33

44
export interface Fetched {
@@ -21,7 +21,7 @@ export interface FetchState {
2121
export type Loaded = {
2222
node: SSRNode;
2323
data: Record<string, any> | null;
24-
server_data: JSONValue;
24+
server_data: any;
2525
};
2626

2727
type CspMode = 'hash' | 'nonce' | 'auto';

packages/kit/src/utils/escape.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const render_json_payload_script_regex = new RegExp(
3737
* Attribute names must be type-checked so we don't need to escape them.
3838
*
3939
* @param {import('types').PayloadScriptAttributes} attrs A list of attributes to be added to the element.
40-
* @param {import('types').JSONValue} payload The data to be carried by the element. Must be serializable to JSON.
40+
* @param {any} payload The data to be carried by the element. Must be serializable to JSON.
4141
* @returns {string} The raw HTML of a script element carrying the JSON payload.
4242
* @example const html = render_json_payload_script({ type: 'data', url: '/data.json' }, { foo: 'bar' });
4343
*/

packages/kit/types/index.d.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { CompileOptions } from 'svelte/types/compiler/interfaces';
77
import {
88
AdapterEntry,
99
CspDirectives,
10-
JSONObject,
11-
JSONValue,
1210
Logger,
1311
MaybePromise,
1412
Prerendered,
@@ -194,18 +192,18 @@ export interface HandleError {
194192
* rather than using `Load` directly.
195193
*/
196194
export interface Load<
197-
Params extends Record<string, string> = Record<string, string>,
198-
InputData extends JSONObject | null = JSONObject | null,
199-
ParentData extends Record<string, any> | null = Record<string, any> | null,
200-
OutputData extends Record<string, any> = Record<string, any>
195+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
196+
InputData extends Record<string, any> | null = Record<string, any> | null,
197+
ParentData extends Record<string, any> = Record<string, any>,
198+
OutputData extends Record<string, any> | void = Record<string, any> | void
201199
> {
202-
(event: LoadEvent<Params, InputData, ParentData>): MaybePromise<OutputData | void>;
200+
(event: LoadEvent<Params, InputData, ParentData>): MaybePromise<OutputData>;
203201
}
204202

205203
export interface LoadEvent<
206-
Params extends Record<string, string> = Record<string, string>,
207-
Data extends JSONObject | null = JSONObject | null,
208-
ParentData extends Record<string, any> | null = Record<string, any> | null
204+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
205+
Data extends Record<string, any> | null = Record<string, any> | null,
206+
ParentData extends Record<string, any> = Record<string, any>
209207
> {
210208
fetch(info: RequestInfo, init?: RequestInit): Promise<Response>;
211209
params: Params;
@@ -235,7 +233,9 @@ export interface ParamMatcher {
235233
(param: string): boolean;
236234
}
237235

238-
export interface RequestEvent<Params extends Record<string, string> = Record<string, string>> {
236+
export interface RequestEvent<
237+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>
238+
> {
239239
clientAddress: string;
240240
locals: App.Locals;
241241
params: Params;
@@ -260,8 +260,6 @@ export interface ResolveOptions {
260260
transformPageChunk?: (input: { html: string; done: boolean }) => MaybePromise<string | undefined>;
261261
}
262262

263-
export type ResponseBody = JSONValue | Uint8Array | ReadableStream | Error;
264-
265263
export class Server {
266264
constructor(manifest: SSRManifest);
267265
init(options: ServerInitOptions): void;
@@ -295,21 +293,23 @@ export interface SSRManifest {
295293
* rather than using `ServerLoad` directly.
296294
*/
297295
export interface ServerLoad<
298-
Params extends Record<string, string> = Record<string, string>,
299-
ParentData extends JSONObject | null = JSONObject | null,
300-
OutputData extends JSONObject | void = JSONObject | void
296+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
297+
ParentData extends Record<string, any> = Record<string, any>,
298+
OutputData extends Record<string, any> | void = Record<string, any> | void
301299
> {
302-
(event: ServerLoadEvent<Params, ParentData>): MaybePromise<OutputData | void>;
300+
(event: ServerLoadEvent<Params, ParentData>): MaybePromise<OutputData>;
303301
}
304302

305303
export interface ServerLoadEvent<
306-
Params extends Record<string, string> = Record<string, string>,
307-
ParentData extends JSONObject | null = JSONObject | null
304+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
305+
ParentData extends Record<string, any> = Record<string, any>
308306
> extends RequestEvent<Params> {
309307
parent: () => Promise<ParentData>;
310308
}
311309

312-
export interface Action<Params extends Record<string, string> = Record<string, string>> {
310+
export interface Action<
311+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>
312+
> {
313313
(event: RequestEvent<Params>): MaybePromise<
314314
| { status?: number; errors: Record<string, string>; location?: never }
315315
| { status?: never; errors?: never; location: string }

packages/kit/types/private.d.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,6 @@ export interface AdapterEntry {
2626
}) => MaybePromise<void>;
2727
}
2828

29-
// TODO is this still used?
30-
export type BodyValidator<T> = {
31-
[P in keyof T]: T[P] extends { [k: string]: unknown }
32-
? BodyValidator<T[P]> // recurse when T[P] is an object
33-
: T[P] extends BigInt | Function | Symbol
34-
? never
35-
: T[P];
36-
};
37-
3829
// Based on https://github.com/josh-hemphill/csp-typed-directives/blob/latest/src/csp.types.ts
3930
//
4031
// MIT License
@@ -145,20 +136,6 @@ export interface CspDirectives {
145136

146137
export type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
147138

148-
export interface JSONObject {
149-
[key: string]: JSONValue;
150-
}
151-
152-
export type JSONValue =
153-
| string
154-
| number
155-
| boolean
156-
| null
157-
| undefined
158-
| ToJSON
159-
| JSONValue[]
160-
| JSONObject;
161-
162139
export interface Logger {
163140
(msg: string): void;
164141
success(msg: string): void;
@@ -229,8 +206,4 @@ export interface RouteSegment {
229206
rest: boolean;
230207
}
231208

232-
export interface ToJSON {
233-
toJSON(...args: any[]): Exclude<JSONValue, ToJSON>;
234-
}
235-
236209
export type TrailingSlash = 'never' | 'always' | 'ignore';

0 commit comments

Comments
 (0)