Repository: sveltejs/kit

Issue #11925: Make App.d.ts route id aware
Created: 2024-03-01T08:46:35Z
Describe the problem
Defining globals for PageData is fine for most of the time. But when you are splitting your app in 2 or more named layouts with with specific data being loaded in +layout.ts / +layout.server.ts it's frustrating to have to force non-null checking for data that will always be there.
For example:
declare global {
	namespace App {
		/** Local data populated by Handle hook */
		interface Locals
		{
			prisma: PrismaClient;
			s3: S3Client;
			
			user: User | null;
			session: Session | null;

			appSettings?: AppSettings; // this is never populated in /install route
			userSettings?: UserSettings; // this is never populated in /install route
		}
	
		/** Page data populated by layouts load function */
		interface PageData
		{
			user: User | null;
			session: Session | null;
			
			appSettings?: AppSettings // this is never populated in /install route
			userSettings?: UserSettings // this is never populated in /install route
		}
	}
}
Leads to having ESLint being completely lost here, as data is there but typed as optional.

Describe the proposed solution
The actual way of defining global app types should not be modified as it works fine for almost everyone. We could add something like:
declare global {

	namespace App {

		// interface Error {}
		// interface Platform {}
                 // interface PageData {} This becomes useless as it is filled with context types

		/** Local data populated by Handle hook */
		interface Locals
		{
			prisma: PrismaClient;
			s3: S3Client;
		}
		
		/** 
		 * Define fine grained types based on route context. 
		 * Routes inherits global types and their corresponding context types 
		 */
		interface Context {

			/** 
                           * Define data based on route context 
                           * `/app/*` would match all routes that begins with /app
                           */
			[`/app/*`] :  {

				locals: {
					appSettings: AppSettings;
					userSettings: UserSettings;
					user: User;
					session: Session;
				}

				pageData: {
					user: User;
					session: Session;
					appSettings: AppSettings;
					userSettings: UserSettings;
				}
			}
		}
	}
}
Alternatives considered
As stated in the docs Use optional properties for data that is only present on specific pages. works fine tbh, juste let ESLint scream at you and be confident about your data structure.
Importance
would make my life easier
Additional Information
No response

Duplicate issue #12867: Route specific locals typings
Created: 2024-10-23T12:06:58Z
Describe the problem
I have an app that has several areas such as /user, /(public), /admin etc.
For each of these areas I set different locals as the needs are different. However the type of locals, as far as i can tell, has to be as general as possible
I would like to tell Typescript "if you are on this route, then you can expect locals to hold this data".
That would reduce my boilerplate a lot, and make it easier to share data between both actions and load functions since It would be easier to populate certain data in the hooks.server.ts (if on a particular route/subtree). Currently I can choose between re-fetching data in actions (data that is loaded in a layout load but not available in actions), or I could load data in a function called by the hooks file (if matching a route) but then I would get a very general type with a lot of optional properties since the type of the object has to match all possible routes.
Describe the proposed solution
I am not sure as I am no typescript wizard, but I imagine that since route.id is already very well typed (i.e. in page file it is a literal string / const, and in layouts it is a union of such), it should be possible to create a route dependet Locals type that could also be part of the $types-family somehow. It cannot just match the current route id however, but routes beginning with /user etc.
I'm not sure where and how it should be configured, I imagine that there are people more suited for that. But perhaps just use the app.d.ts file, or we could also perhaps have a locals.d.ts file in such subfolders. I am not sure what would be best. But I guess that I would like to have a function in hooks.server handle that would make sure that all possibilities are exhausted and that I uphold the contract.
I understand that I still have to uphold my part of the contract in the hooks.server.ts file, making sure that I supply the right data so that the Locals are not lying. But that is already the case (if I type Locals in one way and populate it in hooks.server another way).
All of this should of course be opt in, so that a user that is completely fine with same locals everywhere do not have to bother, but it would be nice if you like me have a application with very well defined areas/subroutes.
Alternatives considered
I don't know, perhaps this is already supported but i have just not been able to create the right Locals type. I mean, it would be nicest if { locals } object in the load / actions would be just typed out of the box, if I have configured that way. But I could also use a type narrowing function which asserts the locals, if I could just figure out how to type it.
Importance
would make my life easier
Additional Information
I DID do a search for this, but I didn't find anything at first. But after looking some more, I found
Allow locals to be typed specifically for subpages of layouts #10194 
 Make App.d.ts route id aware #11925 
(and also #9411)

Closing comment (2024-10-25T08:34:20Z): closing as duplicate of #11925