无需导出prop,指定泛型Modal组件类型的方案问询
Svelte泛型Modal组件的类型关联方案
问题说明
我做了一个泛型Modal组件,能让开发者快速实现模态框功能——比如打开表单录入数据,确认后通过modal.success(...)派发事件,把数据传给<Modal on:success={event => {...}}>的回调。
现在的问题是modal.success(...)和<Modal on:success>之间没建立类型关联。我本来想让组件自动从modal.success(form_data)推断类型,但因为modal.success可以被多处调用,这条路走不通;我希望能像TypeScript里<Modal<MyFormType>>那样直接给Modal指定类型。
试过一种不太好的办法:在Modal组件里加虚拟prop来推断类型,但我不想这么做。另外,我不想在页面全局定义每个模态框的表单数据变量,希望把变量放在Modal的作用域里,同时还能通过modal.success()把结果传给on:success回调。
现有代码示例
+page.svelte
<script> let form_data: MyFormType = { ... }; </script> <Modal on:success={event => {...}}> <button slot="button" let:modal on:click={() => modal.show()}> 显示模态框 </button> <article slot="modal" let:modal> <header> 在自定义表单中输入数据 </header> <MyCustomForm bind:form_data/> <footer> <a href="#cancel" role="button" on:click={() => modal.cancel()}> 取消 </a> <a href="#confirm" role="button" on:click={() => modal.success(form_data)}> 确认 </a> </footer> </article> </Modal>
CustomModal.svelte
<script lang="ts" strictEvents generics="T"> import { createEventDispatcher } from "svelte"; // 要让这里的dispatch类型和success(result: T)函数关联 const dispatch = createEventDispatcher<{success: T}>(); let dialog_element: HTMLDialogElement; let modal_is_shown = false; function show() { dialog_element.showModal(); } function cancel() { dialog_element.close(); } function success(result: T) { dialog_element.close(); dispatch("success", result); } </script> <slot modal={{ show }} name="button"/> <dialog bind:this={dialog_element}> <slot modal={{ cancel, success }} name="modal"/> </dialog>
解决办法
1. 直接给Modal指定泛型类型
你的CustomModal已经用generics="T"声明了泛型,在Svelte 4+里,使用组件时可以直接指定类型:
方式一:用属性指定
<Modal generic:T={MyFormType} on:success={event => { // 这里event.detail会自动被推断为MyFormType类型 console.log(event.detail); }}>
方式二:TypeScript尖括号语法(仅在TS环境下可用)
<Modal<MyFormType> on:success={event => {...}}>
这样就能直接把modal.success(result: T)的参数类型和on:success事件的event.detail类型绑定起来,不需要虚拟prop。
2. 在Modal作用域内定义表单数据
把form_data移到modal插槽的内部脚本里,就能限定在Modal的作用域内,不会污染全局:
<Modal generic:T={MyFormType} on:success={event => {...}}> <button slot="button" let:modal on:click={() => modal.show()}> 显示模态框 </button> <article slot="modal" let:modal> <script> // 这里的form_data只在当前modal插槽作用域内有效 let form_data: MyFormType = { ... }; </script> <header> 在自定义表单中输入数据 </header> <MyCustomForm bind:form_data/> <footer> <a href="#cancel" role="button" on:click={() => modal.cancel()}> 取消 </a> <a href="#confirm" role="button" on:click={() => modal.success(form_data)}> 确认 </a> </footer> </article> </Modal>
关键注意点
- 确保你的Svelte版本是4及以上,因为组件泛型是Svelte 4才正式支持的特性。
- CustomModal里开启了
strictEvents,这会让事件类型被严格检查,保证on:success的回调参数类型和泛型T完全匹配。
内容的提问来源于stack exchange,提问作者Ólavur Nón
相关产品推荐
相关产品推荐

