当我通过 setContext 或 component prop 传递 store 时,如何设置自定义 store 的类型?

luk*_*zyk 5 jsdoc typescript svelte svelte-store sveltekit

使用 SvelteKit 时,必须始终在/store路径中创建,否则会出现刷新后状态保持最新的问题。 您无法在导入的模块中创建 ,因为服务器端模块仅加载一次,这会导致. 所有这些都导致了类型的某种情况。pagelayout
storestore

问题:

我创建商店并将其从 传递+page.svelteChild.svelte,通过setContext


<!-- +page.svelte -->
<script>
  import Child from "./Child.svelte";
  import { writable } from 'svelte/store';
  import { setContext } from "svelte";
  
  function createCount() {
    /** @type {import("svelte/store").Writable<number>} */
    const { subscribe, set, update } = writable(0);
    
    return {
      subscribe,
      increment: () => update(n => n + 1),
      decrement: () => update(n => n - 1),
      reset: () => set(0)
    };
  }
  
  export const count = createCount();
  
  setContext("store", count);
</script>

<Child/>
Run Code Online (Sandbox Code Playgroud)
<!-- Child.svelte -->
<script>
import { getContext } from "svelte";
  
  const count = getContext("store");
</script>

<h1>The count is {$count}</h1>

<button on:click={count.increment}>+</button>
<button on:click={count.decrement}>-</button>
<button on:click={count.reset}>reset</button>
Run Code Online (Sandbox Code Playgroud)

Child.svelte计数类型storeany
奥布拉兹

它应该像声明的地方一样:
奥布拉兹

这就是store从 getContext("store") 返回的的类型:

const count: {
    subscribe: (this: void, run: Subscriber<number>, invalidate?: Invalidator<number> | undefined) => Unsubscriber;
    increment: () => void;
    decrement: () => void;
    reset: () => void;
}
Run Code Online (Sandbox Code Playgroud)

路过也<Child {count}/>有同样的问题。
奥布拉兹

问:如何做到这一点?

选择

事实并非如此。您只能在模块中创建store并导入它 - 然后保留类型。
但这会产生一些store有效性问题,正如我在开头所写的。

H.B*_*.B. 4

有两个主要选项:使用preprocess-svelte和编写 TypeScript 或添加 JSDoc 类型注释。

与 TS:

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

    // Prop
    export let count: StoreType;

    // Context
    const store = getContext<StoreType>('context');
</script>
Run Code Online (Sandbox Code Playgroud)

使用 JSDoc:

<script>
    import { getContext } from 'svelte';

    // Prop
    /** @type {StoreType} */
    export let count;

    // Context
    /** @type {StoreType} */
    const store = getContext('context');
</script>
Run Code Online (Sandbox Code Playgroud)

您可以在单独的文件中声明类型.d.ts或使用@typedef.


createCount函数可以毫无问题地提取到单独的文件中。这样,在输入 props/context 时也可以使用它的返回类型。例如

// create-count.js
import { writable } from 'svelte/store';

export function createCount() {
    const { subscribe, set, update } = writable(0);

    return {
        subscribe,
        increment: () => update(n => n + 1),
        decrement: () => update(n => n - 1),
        reset: () => set(0),
    };
}
Run Code Online (Sandbox Code Playgroud)
<script>
    import { getContext } from 'svelte';

    /** @type {ReturnType<import('./create-count').createCount>} */
    export let count;

    /** @type {ReturnType<import('./create-count').createCount>} */
    const store = getContext('context');
</script>
Run Code Online (Sandbox Code Playgroud)

在 TS 中,这更清晰,因为您可以将类型作为常规代码的一部分导入并使用类型别名。

<script lang="ts">
    import type { createCount } from './create-count';
    import { getContext } from 'svelte';

    export let count: Count;

    const store = getContext<Count>('context');

    type Count = ReturnType<typeof createCount>;
</script>
Run Code Online (Sandbox Code Playgroud)