Closed KevsRepos closed 6 months ago
This exists, no?
<script lang="ts">
import type { Props } from './common';
let { x, y, z, ...rest }: Props = $props();
</script>
This exists, no?
<script lang="ts"> import type { Props } from './common'; let { x, y, z, ...rest }: Props = $props(); </script>
Importing the type works but only when using typescript or jsdoc at least. Also, it just makes sure you stick to the type definition, but you still have to repeat the entire declaration of your props in every component.
After experimenting with $props()
I found out you can create something like an "abstract" component and use composition:
https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAA5WR3U7EIBCFX2VCvNhNGnpfsf49hnixpTQSy09gutmV8O4WabfGxI1eDWfIx5w5RDKoUQbSvERiDlqShjw6RyqCZ5dFOMoR5ayDnbzIHRaEVw5bbjgq7axHeJoQrYHBWw2c0LpoWlhObrlh9UYZVu7b51GJd9CSLUA7j9G2V4OSPWnQTzJVm6suoD8I_Ks1YU1AiPk4izc19l6aqsjTUs9L_cglwR3cOG9d2O1_Oo4PM9xLD-tD93S3T9fslo3-meO645bk2vme5WU3oJR-GYZr3llXws0gu0yIK5ugbjPR_fYFr-kTjUovrCQCAAA=
But it doesnt play well with types and especially not with snippet types.
What do you mean by "it doesn't play well with types and especially not snippet types"?
In general, I don't see how this will make anyone's lives easier, nor will it solve use cases more elegantly.
const myProps = $props.use(shared);
or just const { foo, bar, .. } = $props()
, you won't be saved from adjusting components when you change a property nameYeah, I'm having a real hard time understanding why this...
const x = $props.use(shared);
...is better than this:
const { ...x } = $props();
And what is shared
? In the example above...
export const shared = {children, x, y, z, foo} = $props.definition();
children
, x
, y
, z
and foo
must refer to declarations in scope otherwise all you've got is a bunch of reference errors. So are people actually supposed to do this?
let children;
let x;
let y;
let z;
let foo;
export const shared = {children, x, y, z, foo} = $props.definition();
It all seems a bit confusing to me.
Do you want something like this?
export type SharedUtilsTypes = {
class?: string,
border?: string,
rounded?: number,
expanded?: boolean,
}
export function sharedAction(elem, { class: className, border, rounded, expanded }: SharedUtilsTypes) {
// some shared code
}
export function helperFunction({ class: className, border, rounded, expanded }: SharedUtilsTypes) {
// another shared code
return ...
}
<script lang="ts">
import { SharedUtilsTypes, sharedAction, helperFunction } from "./sharedUtils.ts";
type MyTypes = SharedUtilTypes & {
x: number,
y: string,
z?: boolean,
}
let { x, y, z, ...sharedProps }: MyTypes = $props();
let foo = helperFunction(sharedProps);
</script>
<div use:sharedAction={sharedProps}>
some content
</div>
Given that there are various sensible solutions to different use cases and because I can't imagine this getting easier with a separate rune, I'm going to close this
There is one problem with Snippets and typescript though. https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAA52SPU_DMBCG_8rJYmilKNlDW-jGiMSIGUJyAUuJbdmXqsjyf8d2YrWUCgGbz76P5319jvViQMvqZ8dkMyKr2V5rVjD60DGwBxwIQ2zVZNp4s7GtEZpgaOTbljOynO24FKNWhuABmw4N9EaNwFlZzXE5d-HslstNNdeHmhAs-dUuTBhVJ3qBHavJTOiLE9CrJdO09BuqVknCIwWw0G4aMMHhMcGJ8GT6pkXIHR-N0hZcQKH2XQydQVnDkxRaIxVc-kvcq9I5LeIjHLhcDz7bcKaeU5qlpKV57GlwEUNfX7Bt4UbHw2r9zbtOHNJ0dx-qo4u50125Wif0mPGTsbP7__7sTFoE0Un7F3R_2oJ8f74HXC4uQFmWSSL8RXxOBJfL_dUtevGf_kQeReICAAA=
While the solution with the abstract component works in principle, it is impossible to properly type snippets when using this pattern. When you use the Snippet
type from the svelte package, ts will yell that
Property 'children' is missing in type '{}' but required in type 'AbstractProps'
When trying to allow nullification (children?: Snippet
, {@render children?.()}
), we get
Argument of type '(unique symbol & { _: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\""; }) | undefined' is not assignable to parameter of type 'unique symbol & { _: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\""; }'.
Type 'undefined' is not assignable to type 'unique symbol & { _: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\""; }'.
Type 'undefined' is not assignable to type 'unique symbol'.
Maybe this problem deserves its own issue?
The nullification approach is the right solution - there was a bug within language tools that caused this type error which was fixed yesterday, make sure you're using the latest version of svelte-check and the VS Code extension
Describe the problem
Often enough you have a set of components which all belong to the same domain, meaning they share a lot of structure and their props. Threlte is definitely one of the bigger examples, but usually every component library has this issue.
The Threlte Maintainer found a way to share props between components by inventing an inheritance model for Svelte components.
<Foo.Bar />
whereFoo
defines a base set of props that automatically apply toBar
.As far as I know, there is no such concept in Svelte. Maybe we dont even have to implement it. I just wanted to give a real life example where a lot of effort had to be put in to solve the critical problem of ever repeating prop definitions across multiple components.
Many component libraries often share "base" props between every component. Whether its a
<Button />
,<Input />
or a<Card />
- all of them need aclass
prop to extend styles, or maybe aborder
,rounded
orexpand
prop.As far as I know, the only method to accomplish this, is to manually define every prop individually on every component. And dare a prop changes or is added, you can iterate over every component again.
Describe the proposed solution
One method to solve the props issue:
Less repetitive and still flexible.
Importance
would make my life easier