question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Generated types for pages/endpoints

See original GitHub issue

Ways that types in SvelteKit apps could be improved:

Implicit params and props for load functions (update: done)

<script context="module">
  /** @type {import('@sveltejs/kit').Load */
  export async function load({ params, fetch }) {
    // `params` automatically typed from filename (e.g. `src/routes/blog/[slug]`)
    const res = await fetch(`/blog/${params.slug}.json`);
    const { post } = await res.json();

    return {
      props: {
        // `post` type automatically inferred from component props
        post
      }
    };
  }
</script>

<script>
  /** @type {BlogPost} */
  export let post;
</script>

Similarly, with shadow endpoints, it would be good to type body based on component props (though this could be tricky since component props combine e.g. post and get bodies), and also type the props input to load in cases where it’s used.

It might be possible to do something clever with rootDirs, or with preprocessors?

Typed goto and fetch

As mentioned below, it might be possible to type functions like goto based on the available routes. It probably gets tricky with relative routes, but that could be a bailout.

Typed links

This is a little tricky for us, since we use <a> instead of <Link>, but it would be neat if it was possible to typecheck links somehow.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:31
  • Comments:16 (15 by maintainers)

github_iconTop GitHub Comments

11reactions
ivanhofercommented, Dec 23, 2021

Originally posted in #3090, here I describe how goto, fetch (and like @ebeloded mentioned invalidate, prefetch, prefetchRoutes) could be improved with some type-information:

Describe the problem

In larger projects (also in smaller projects) it would be great if the goto and the fetch functions could offer more typesafety. Problems with missing typesafety are:

  • typos when you link to a route that does’t exist e.g. /costumer instead of /customer
  • help for refactorings e.g. when renaming larger chunks of files inside the routes folder, all links need to be updated too
  • trying to call fetch with the wrong method e.g. using PUT instead of PATCH

It would be great if the goto and the fetch functions could output an error when you pass in a invalid relative slug.

Describe the proposed solution

The problem could be solved by providing advanced TypeScript types for the goto and the fetch function. Similar tho the already generated .svelte-kit/dev/generated/manifest.js file, SvelteKit could generate a d.ts with types depending on the .svelte files inside the routes folder and depending on the function inside a .js and .ts Endpoints file.

These types then could be used to enhance the goto and fetch functions. The typesafe functions could replace the existing import from app/navigation. I’m not sure how this could work for the fetch function since you don’t really import it from anywhere. Or this could be an additional function you need to import from app/typesafe or something similar.

Here is a working example how I think this could look like:

  • helper-types: for cheching if a slug is valid

type SplitPath<S extends string> =
	S extends `/${infer Part}/${infer Rest}`
		? ['/', Part, '/', ...SplitPath<Rest>]
		: S extends `${infer Part}/${infer Rest}`
			? [Part, '/', ...SplitPath<Rest>]
			: S extends `/${infer Part}`
				? ['/', Part]
				: S extends ''
					? []
					: S extends `${infer Part}`
						? [Part]
						: []

type RemoveEmptyEntries<A extends Array<unknown>> =
	A extends []
		? []
		: A extends [infer Item, ...infer Rest]
			? Item extends ''
				? RemoveEmptyEntries<Rest>
				: [Item, ...RemoveEmptyEntries<Rest>]
			: []
  • routes: for the goto function
// alias type to get better TypeScript hints inside tooltips
type id = string

// this type is dynamic and get's generated
type Routes =
	| ['/'] // index.svelte
	| ['/', 'about'] // about/index.svelte
	| ['/', 'products'] // products/index.svelte
	| ['/', 'products', '/', 'create'] // products/index.svelte
	| ['/', 'products', '/', id] // products/[id]/index.svelte
	| ['/', 'products', '/', id, '/', 'edit'] // products/[id]/edit.svelte

export type IsValidRoute<R extends string> =
	R extends `http${string}`
		? R
		: RemoveEmptyEntries<SplitPath<R>> extends Routes
			? R
			: 'No such Route'

const goto = <Route extends string>(href: IsValidRoute<Route>): void => {
	// TODO: goto href
}

// @ts-expect-error
goto('')
goto('/')
goto('/about')
// @ts-expect-error
goto('/invalid')
// @ts-expect-error
goto('/product')
goto('/products')
// @ts-expect-error
goto('/products/')
// @ts-expect-error
goto('/products/create/')
goto('/products/123456')
// @ts-expect-error
goto('/products/123456/')
// @ts-expect-error
goto('/products/123456/add')
goto('/products/123456/edit')
// @ts-expect-error
goto('/products/123456/5678/edit')

goto('https://kit.svelte.dev')
  • endpoints: for the fetch function
type Methods =
	| 'GET'
	| 'POST'
	| 'PUT'
	| 'PATCH'
	| 'DELETE'

// this type is dynamic and get's generated
type Endpoints = {
	GET:
	| ['/', 'products']
	| ['/', 'products', '/', id]
	POST:
	| ['/', 'products']
	PATCH:
	| ['/', 'products', '/', id]
}

export type IsValidEndpoint<M extends Methods, R extends string> =
	R extends `http${string}`
		? R
		: M extends keyof Endpoints
			? RemoveEmptyEntries<SplitPath<R>> extends Endpoints[M]
				? R
				: 'No such Endpoint'
			: 'No such Method'

const fetch = <Endpoint extends string, Method extends Methods = 'GET'>(endpoint: IsValidEndpoint<Method, Endpoint>, options?: { method?: Method, [key: string]: any }): void => {
	// TODO: call fetch
}

fetch('/products')
// @ts-expect-error
fetch('products')
fetch('/products/12345')
fetch('/products', { method: 'POST' })
// @ts-expect-error
fetch('/products', { method: 'PATCH' })
// @ts-expect-error
fetch('/products/12345', { method: 'POST' })
fetch('/products/12345', { method: 'PATCH' })

fetch('http://example.com/articles')

You can copy these examples to a .ts file and try passing some valid/invalid strings to the goto and fetch functions. Lines annotated with // @ts-expect-error are invalid and will throw a TypeScript Error.

3reactions
Rich-Harriscommented, May 13, 2021
export async function load({ milieu }) {
  return {
    milieu: {...}
  };
}

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Generate GraphQL Types with Apollo Codegen Tutorial
In this post, you'll learn how to use Apollo's GraphQL codegen to generate TypeScript types for GraphQL operations in your Apollo Client ...
Read more >
Automatically Generate TypeScript Types For Your ... - YouTube
With StepZen you can build a GraphQL API for any data source in minutes, and deploy it to the cloud in seconds.
Read more >
Generate TypeScript Types from GraphQL - Fullstack.io
This post shows you how to generate TypeScript types from your GraphQL server. And it's super handy because not only is your code...
Read more >
Generated Types | RedwoodJS Docs
To add to the TypeScript (and JavaScript!) experience, Redwood generates types for you. These generated types not only include your GraphQL operations, but...
Read more >
Automatically generate Typescript types ... - DEV Community ‍ ‍
Introduction In this post, I will show you how to automatically generate types for your... Tagged with typescript, graphql, javascript, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found