Svelte中的TypeScript事件参数类型

27

我刚接触Svelte,但它非常小巧,非常适合我正在开发的项目。

选择了TypeScript选项:https://svelte.dev/blog/svelte-and-typescript

如何或者在哪里可以找到自定义组件事件的类型:

一个简单的登录组件表单:

<script lang="ts">
  import { createEventDispatcher } from 'svelte'

  const dispatch = createEventDispatcher()
  let isSubmitting = false
  const handleSubmit = (e: HTMLFormElement) => {
    e.preventDefault()
    isSubmitting = true
    const payload = {
      username: e.target.username.value,
      password: e.target.password.value,
    }
    dispatch('submit', payload)
  }
</script>

<form on:submit={handleSubmit}>
    <label for="username"><b>Username</b></label>
    <input type="text" placeholder="Enter Username" name="username" required id="username">

    <label for="password"><b>Password</b></label>
    <input type="password" placeholder="Enter Password" name="password" required id="password">

    <button type="submit" disabled={isSubmitting}>Login</button>
</form>

包含在另一个组件中以处理提交:

<script lang="ts">
  import Login from './molecules/Login.svelte'
  const loginHandle = function (a: any) {
    console.log(a)
  }
</script>

<main class="{open}">
   {#if !authenticated}
      <Login on:submit={loginHandle}/>
   {/if}
</main>

现在 loginHandle 里面有一个不太好看的 any,但是把事件转储到控制台时它看起来非常特定于 Svelte... 我该在哪里找到类型?


我猜你可以使用“事件”来输入它。 - johannchopin
是的 - 添加了detail和explicitOriginalTarget。Detail包含开发人员感兴趣的有效负载,我猜想在某个SvelteEvent类型中也应该有这些内容。 - user1037355
2
Svelte没有自定义事件类型,因为它们是原生的JavaScript事件。它们不像React那样伪造一些事件并具有自定义类型。因此,您可以使用“Event”类型,这应该没问题。我应该将其写成答案吗? - johannchopin
4个回答

38

为了进行完整的输入,请将事件触发器更改为:

const dispatch = createEventDispatcher<{submit:{username:string, password:string}}>()

并将事件消费者指定为:

const loginHandle = function (a: CustomEvent<{username:string, password:string}>) {
    console.log(a.detail.username) //username is type string
    console.log(a.detail.password) //password is type string
}

这将导致调用 dispatch("submit", "wrongDetailType") 失败,并且会消除处理程序中 a.detail 的类型为 "any"。


1
这太棒了!但是我注意到当没有传递任何细节时调用dispatch时,它不会引发错误,签名仍然是details?:[type]。你知道有什么方法可以改变这个吗?如果我想给我的细节指定类型,我希望确保它们存在。编辑似乎不可能:https://github.com/sveltejs/svelte/blob/222a9dd/src/runtime/internal/lifecycle.ts#L32 - Cédric Van Rompay

9

如何或者在哪里可以找到自定义组件事件的类型:

你可以向 createEventDispatcher 函数的泛型参数中传递一个对象。其中,键表示自定义事件的名称,值为一个详细对象。

子组件 (<Calendar />)

<script lang="ts">
  import { createEventDispatcher } from 'svelte'

  const dispatch = createEventDispatcher<{ select: Date }>()

  function onSelect(date: Date): void {
    dispatch('select', date)
  }
</script>

...

父组件

<script>
  function handleSelect (event: CustomEvent<Date>) {
    console.log('Selected date', event.detail)
  }
</script>

<Calendar on:select={handleSelect} />

使用示例

在此输入图片描述


这种方法的问题在于它没有将处理程序和发射器绑定在一起。你可以随意使用 createEventDispatcher<{timestamp: Date}>handle(event: CustomEvent<string>),这样重构就变得很麻烦。 - Kevin Cox

4

Svelte现在配备了CustomEvent接口定义。因此,您可以将函数声明为以下格式。

const loginHandle = function (a: CustomEvent) {
    console.log(a)
}

1
你甚至可以通过使用CustomEvent<SomeType>来输入CustomEvent的详细成员。请参见下面的答案。 - DoomGoober
2
这实际上并没有回答问题。即使您使用 CustomEventdetail 属性仍将是 any - aradalvand

3

我发现使用 Svelte 事件系统不可能实现此功能。您可以在每一侧声明类型,但目前没有任何方式来验证组件中的类型(或者甚至是事件名称)是否与使用该组件的代码中的类型匹配。

但是,可以通过回调属性而非事件来解决这个问题。我知道唯一的缺点是 onSubmit 名称比 on:submit 作为回调 / 事件不够明显,并且需要声明要传播的事件。总的来说,这似乎是为了同时对事件名称和事件值进行类型检查所付出的很小代价。您还可以创建必需的回调函数,这对于不听特定事件就没有意义的组件非常有用。

示例

这是原始问题中代码的最小化示例。

组件

<script context="module" lang="ts">
    export interface Payload {
        username: string,
        password: string,
    }
</script>
<script lang="ts">
    export let onSubmit: (payload: Payload) => void;

    function handleSubmit(e: SubmitEvent) {
        e.preventDefault()
        onSubmit({
            username: e.target.username.value,
            password: e.target.password.value,
        });
    }
</script>

<form on:submit={handleSubmit}>
    <input name=username required>
    <input type=password name=password required>
    <button type=disabled>Login</button>
</form>

注意:要使处理程序可选,只需将一个空操作函数设置为默认值即可:
export let onSubmit: (payload: Payload) => void = () => {};

调用者

<script lang="ts">
    import Login from "./Login.svelte"
    import type {SubmitEvent} from "./Login.svelte"
    function handleLogin (event: SubmitEvent) {
        console.log(event)
    }
</script>

<main>
    <Login onSubmit={handleLogin}/>
</main>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接