Improving dynamic TS package ergonomics
- 主要言語
- Rust
- スター
- 30.5k
- フォーク
- 3.2k
- 平均マージ
- 2日 8時間
- マージ済み PR(30日)
- 60
説明
Re https://github.com/ankitects/anki/pull/1626#issuecomment-1024622000, 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
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(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;
+ lifecycle: LifecycleHooks;
+ instances: NoteEditorAPI[];
+ }
+ const noteEditorPackage = {
context,
lifecycle,
instances,
- });
+ } as NoteEditorPackage;
+ registerPackage("anki/NoteEditor", noteEditorPackage as any);
```
Add-ons could then use require() with a cast to get a typed module:
```typescript
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:
```typescript
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?
```typescript
import { NoteEditor } from "@anki/runtime"
```
One other thing I noticed while looking at https://github.com/hgiesel/anki_new_format_pack/pull/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?
コントリビューションガイド
評価
この issue はまだ評価されていません。