-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Re #1626 (comment), I've been hunting for a way to make this a bit less cumbersome & more robust than manually declaring the exports. What if instead, we export the module's interface in the same place as we register it, ensuring that the interface matches what we're exporting? Eg
diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte
index 957b07616..51747d084 100644
--- a/ts/editor/NoteEditor.svelte
+++ b/ts/editor/NoteEditor.svelte
@@ -17,8 +17,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
import { registerPackage } from "../lib/runtime-require";
- import contextProperty from "../sveltelib/context-property";
- import lifecycleHooks from "../sveltelib/lifecycle-hooks";
+ import contextProperty, { ContextProperty } from "../sveltelib/context-property";
+ import lifecycleHooks, { LifecycleHooks } from "../sveltelib/lifecycle-hooks";
const key = Symbol("noteEditor");
const [context, setContextProperty] = contextProperty<NoteEditorAPI>(key);
@@ -26,11 +26,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export { context };
- registerPackage("anki/NoteEditor", {
+ /** anki/NoteEditor */
+ export interface NoteEditorPackage {
+ context: ContextProperty<NoteEditorAPI>;
+ lifecycle: LifecycleHooks<NoteEditorAPI>;
+ instances: NoteEditorAPI[];
+ }
+ const noteEditorPackage = {
context,
lifecycle,
instances,
- });
+ } as NoteEditorPackage;
+ registerPackage("anki/NoteEditor", noteEditorPackage as any);
</script>
<script lang="ts">
Add-ons could then use require() with a cast to get a typed module:
import type { NoteEditorPackage } from "@anki/editor/NoteEditor.svelte";
const NoteEditor = require("anki/NoteEditor") as NoteEditorPackage;
I spent some time trying to make this work in the context of a 'declare module' so we could keep the standard TS-style import, but couldn't figure out a way to spread the interface into the module definition except by doing so manually:
declare module "anki/NoteEditor" {
type Package = import("@anki/editor/NoteEditor.svelte").NoteEditorPackage;
export const context: Package["context"];
export const lifecycle: Package["lifecycle"];
export const instances: Package["instances"];
}
At least we're not juggling types that way, but it's still extra work. Maybe there's some way I'm not aware of?
If not, perhaps one other option would be to define a .ts file that does the require/cast for this and other modules and exports the resulting symbols, so add-ons could just do something like the following?
import { NoteEditor } from "@anki/runtime"
One other thing I noticed while looking at hgiesel/anki_new_format_pack#11 is that we're currently exporting components
as a global. Could we be stuffing that into a runtime module somewhere instead to make it more discoverable, and typed?