sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.6k stars 4.21k forks source link

Svelte5 JSDoc for `$props` #10541

Closed dreitzner closed 6 months ago

dreitzner commented 8 months ago

Describe the problem

When declaring props with TS, we can add JSDoc comments and type annotations:

interface Props {
    /**
     * This is an important optional count
    */
    count?: number;
}

let { 
    count = 0
} = $props<Props>();

This will show all the info also in intellisense when the component is used: image

But when not using TS, I don't think there is a way to pass that extra info to the LSP.

Describe the proposed solution

It might be nice to add the possibility to augment the destructured props like this:

let { 
    /**
     * This is an important optional count
     * @type {number}
    */
    count
} = $props();

There might be already a working solution out there, that I'm not aware of....

In that case I'd be happy to add it to the docs :)

Importance

nice to have

dummdidumm commented 8 months ago

You can use typedef for this:

/**
 * @typedef Props
 * @property {number} count Some documentation
 */

/** @type {Props} */
let { count } = $props();

Giving this the documentation label to note this wherever in the final new docs we're going to talk about typing stuff.

dreitzner commented 8 months ago

@dummdidumm this does not seem to work at the moment.

If I do a typedef inisde of a normal <script /> block I get the following error:

image

sheijne commented 8 months ago

@dummdidumm this does not seem to work at the moment.

If I do a typedef inisde of a normal <script /> block I get the following error:

@dreitzner It does work:

Screenshot 2024-02-20 at 20 18 46

Nonetheless the error occurs in different IDE's and is definitely a bug. There are more options though:

  1. Define the type inline with an object literal:
    <script>
    /** @type {{ count: number }} */
    let { count } = $props();
    </script>

2.a. Define the type in a separate definition file:

// Counter.d.ts

interface CounterProps {
  count: number;
}
// Counter.svelte
<script>
  /** @type {CounterProps} */
  let { count } = $props();
</script>

2.b. Though in most cases it would probably be more useful to make the definition file a module:

// Counter.d.ts

export interface CounterProps {
  count: number;
}
// Counter.svelte

<script>
  /** @type {import('./Counter').CounterProps} */
  let { count } = $props();
</script>
  1. If you really wanted to you could also use <script lang="ts" context="module"> (though it seems the LSP implicitly "adds" lang="ts" to the second script, which in my opinion is a bug):
    
    <script lang="ts" context="module">
    export interface CounterProps {
    count: number;
    }
    </script>
dummdidumm commented 8 months ago

The code I gave is correct, there's a bug in the VS Code Svelte extension which I fixed in https://github.com/sveltejs/language-tools/pull/2294, release pending.

dreitzner commented 8 months ago

@dummdidumm thank you so much for the explenation and the fix :)

theetrain commented 6 months ago

The @typedef method works for me. I tried using @param, but was not successful:

<script>
  /**
   * @param {Object} Props
   * @param {string} Props.name
   */
  let { name, age, date } = $props()
</script>

<p>Your {name}</p>
<!--     ^ type is `unknown` -->

Can we allow this method of documentation and typing? It could save a couple of lines.

It seems to work with plain JS: playground.

brunnerh commented 6 months ago

That's invalid syntax, the types just come from inference based on the assigned value.

You can do something like this:

/**
 * @type {{
 *  name: string,
 *  age: number,
 *  ...
 * }}
 */
let { name, age, date } = $props()
theetrain commented 6 months ago

Thanks for educating me; I don't know why I thought @param could be used for anything except functions. I suppose @typedef + @property are ideal for documentation, and @type for just types.

I was hoping @typedef can be applied in one step, but that's not possible. All good.