svelte
svelte copied to clipboard
Svelte5 JSDoc for `$props`
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:
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
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.
@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:
@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:
Nonetheless the error occurs in different IDE's and is definitely a bug. There are more options though:
- 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>
- 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>
<script>
/** @type {CounterProps} */
let { count } = $props();
</script>
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.
@dummdidumm thank you so much for the explenation and the fix :)
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.
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()
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.