-
-
Notifications
You must be signed in to change notification settings - Fork 204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(rework) extend from svelte2tsx base class #386
(rework) extend from svelte2tsx base class #386
Conversation
Things like `$$prop_def` live in a `Svelte2TsxComponent` base class now. Saves some characters per transformation and opens up the door for easier manual `d.ts` creation.
Thinking about generic props and defining dependencies between props/slots/events, maybe it's better to have one big generic with all parts instead. |
The problem with generics is hard. Slots/events are generated something like |
Not sure of the use case for generic props, are they for generic
components? If so just using unknown should be enough
…On Sat, 1 Aug 2020, 7:33 pm Simon H, ***@***.***> wrote:
The problem with generics is hard. Slots/events are generated something
like __sveltets_instanceof(Component) - how to get the generic in there?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#386 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAEGS5GSLA7QKRYBACI7HXTR6POPPANCNFSM4PN2BGFA>
.
|
The use case for generics would be to be able to express something like this:
So that this would give an error <Component items={[1,2]} let:item={item}>
{item.toLowerCase()} // <--- error, is number, not string
</Component> |
I don't see a clean way of doing this. I think the best we can do is support typescript expressions in the template, |
@@ -94,3 +97,14 @@ declare function __sveltets_each<T>( | |||
array: ArrayLike<T>, | |||
callbackfn: (value: T, index: number) => any | |||
): any; | |||
|
|||
declare class Svelte2TsxComponent<Props = {}, Slots = {}, Events = {}> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be ideal for this to also extend SvelteComponent, maybe this can be an interface instead?
We want instanceOf checks to work instead of returning ("This can never be true"), it would also make our exported .d.ts files generated from this compatible with the svelte component api
(I know the old code didn't do this, but that was due to type conflicts I was having with svelte @types, I think this was resolved)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah was thinking the same, we should extend from the base class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhm, we cannot extend from it, because we need to redeclare the component ourselves at the top. But we can at least copy the interface and constructor, so they are structurally (almost) the same (except for $$prop_def / $$slot_def
).
The generics work if they are only within the props, so TS can infer that. Maybe there is a way to infer the type (haven't testet it yet) for generics between props and slots/events: instead of doing I think adding TS support to the template will not help because of the way svelte2tsx currently generates code for slots/events. Explicitly typing things will not help when people want to express dependencies between props and slots/events. |
I confirmed generics will work if we change the generation for slots/events from declare class Svelte2TsxComponent<Props = {}, Slots = {}, Events = {}> {
constructor(options: {
target: Element;
anchor?: Element;
props?: Props; // <-- this is where the magic happens
hydrate?: boolean;
intro?: boolean;
$$inline?: boolean;
});
$$prop_def: Props;
$$slot_def: Slots;
$on: SvelteOnAllEvent<Events>;
$destroy(): void;
$set(props: Partial<Props>): void;
} I will leave this out of this PR though because we first need to agree on a way to define the generics inside a Svelte file. |
I updated the typings. I switched slots/events because I think events are more likely to be used/typed than slots, so slots is now last. The type error at the top of the @jasonlyu123 @halfnelson could you have one more look if this makes sense to you? The new // index.d.ts definition file:
import { SvelteComponent } from 'svelte2tsx';
export class MyPublicComponent extends SvelteComponent<{propA: boolean}, {eventB: CustomEvent<boolean>}, {slotC: boolean}> {} I briefly thought about asking to add the component type definition to the main repo, but I'm not sure they would accept it due to the |
Overall ok with the direction 😀. Some suggestion/idea:
|
Not sure what you mean,
To clarify: The
Good idea! Will do. |
Make it a method instead of a property but this is no very important. |
Ah I understand. I honestly don't know how to rework this into a method and preserve proper typing 😄 So I'll leave it as a property which is a function now. |
@jasonlyu123 I found a way to type the |
fwiw, I used generics extensively in the past, to make safer component API. An example would be a dropdown/comboBox component with the following, simplified interface (in React): interface ComboBoxProps<ITEM> {
items: Array<ITEM>;
selectedItem?: ITEM;
itemRenderer: (item: ITEM) => VNode;
onSelectItem: (item: ITEM) => void;
} |
Something like that will be possible with the new class. Definition: class Combobox<ITEM> extends Svelte2TsxComponent<{items: ITEM[]}, {selectItem: CustomEvent<ITEM>}> {} Usage: <script lang="ts">
let items = ['a', 'b'];
</script>
<Combobox items={items} on:selectItem={item => {/*item is of type string*/} /> Getting the |
I found the event forward from the component is not working anymore. But upon further investigation, I found my original implementation doesn't work properly either lol and my original way is even more problematic. I'll create another PR if I somehow find a way to do it. |
What exactly does not work? I tested with Child: <script lang="ts">
export let aProp: string;
</script>
<slot aSlot="{aProp}" />
<button on:click></button> Parent: <script>
import Child from './Child.svelte';
</script>
<Child aProp="{''}" let:aSlot="{joo}" on:click="{(e) => e}">{joo}</Child> And props/slots/event was typed correctly |
<script>
import Child from './Child.svelte';
</script>
<Child on:click aProp="{''}" let:aSlot="{joo}" on:click="{(e) => e}">{joo}</Child> Ancestor <script>
import Parent from './Parent.svelte';
</script>
<Parent aProp="{''}" let:aSlot="{joo}" on:click="{(e) => e}">{joo} /> I originally want this |
Aaah I get it now, thanks for explanation. I'll also have a look later hopefully at this. |
Things like
$$prop_def
live in aSvelte2TsxComponent
base class now.Saves some characters per transformation and opens up the door for easier manual
d.ts
creation.Would now look something like this:
Thoughts @orta @halfnelson @jasonlyu123 ?
TODO