sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.59k stars 1.92k forks source link

Allow `App.PageState` to be a union type #11719

Open marekdedic opened 9 months ago

marekdedic commented 9 months ago

Describe the problem

I want to have typechecked history state, so after some googling, I found I could do it with App.PageState like this:

declare global {
  namespace App {
    export interface PageState {
      // Declare properties here
    }
  }
}

export {};

However, I am using the page state to open modals for e.g. editing stuff, so I want to sometimes save some data in the state. Ideally, I would like to be able to use something like a union to represent this

Describe the proposed solution

declare global {
  namespace App {
    export type PageState =
      | {
           type: "listFoo";
        }
      | {
            type: "addFoo";
            fooID: string;
        };
  }
}

export {};

But this doesn't work

Alternatives considered

type Temp =
  | {
       type: "listFoo";
    }
  | {
        type: "addFoo";
        fooID: string;
    };

declare global {
  namespace App {
    export interface PageState extends Temp {}
  }
}

export {};

This doesn't work either...

Importance

nice to have

Additional Information

No response

dummdidumm commented 9 months ago

I don't see a good way to achieve this. Declaration merging does not work with types. But we also cannot just omit the empty interfaces from our own types, because it would mean that people who don't have a App namespace declaration in their project would get type error ("PageState does not exist on namespace App").

marekdedic commented 8 months ago

Hmm, I get that you can't just omit it. I don't understand how Svelte uses these types to fully evaluate any solution, but 3 ideas come to mind - inheritance, generics and module augmentation...

I will try to see if there's any practical way to get those to work...

Apart from that, maybe the way would be to declare the "default" PageState type only if the user didn't declare it? SvelteKit controls the build process so that should be possible, right? Or am I missing something?