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
Improve typecheck for svelte:component bind:this #1214
Conversation
Also, I'd like to ask if more end-to-end testing of this ecosystem (mainly svelte2tsx via svelte-check) was considered? Is there an issue open for this? Because as we can see above, #363 looked like a good idea, but only after release it turned out to break some usage, which couldn't really be thought of when approving the changes in generated tsx. For this PR, here's a test repo: https://github.com/mvolfik/fictional-potato (see steps in readme) For reference: v2.2.7
This PR:
|
Didn't look at the code yet, but to answer some of your points:
|
str.overwrite(attr.start, attr.expression.start, '{...__sveltets_1_empty(('); | ||
str.appendLeft(attr.expression.end, ' = __sveltets_1_instanceOf('); | ||
if (el.name === 'svelte:component') { | ||
str.copy(el.expression.start, el.expression.end, attr.expression.end); |
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.
I don't think that we need copy here, I don't see the need to have both mappings, the instanceOf(Component)
thing does not need a reference to the original. Rename will work as it will add changes to the Svelte file, which does only have the this={Component}
reference, which will trigger another Svelte->tsx transformation. Diagnostics will probably not span the whole element but that's acceptable to me (or could be handled specifically)
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.
i'm sorry, i don't understand what you're saying. could you please explain it better/use other words?
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 I expressed myself poorly here 😄 Maybe we turn it around: Could you explain why you think we need copy here?
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.
my thought process:
bind:this
assigns a reference to the instance to the specified variable- for normal components, the instance is just
instanceof(ComponentClass)
- however, for
svelte:component this={expression}
, the expression could be anything, so it'sinstanceOf
whatever is in thethis={}
clause - I have no idea if there's some typechecking on the
this={}
- but there certainly could be something checking if it's [a component class or null], so I don't want to move it away, but instead copy
so if you were asking is why am I choosing to 'smart'-copy it with source mapping instead of just appending the string just like when it's a normal component, well, I have honestly no idea - it just looked like the right way to do it
} else { | ||
str.appendLeft(attr.expression.end, thisType); | ||
} | ||
str.overwrite(attr.expression.end, attr.end, ') || null))}'); |
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.
I'm not 100% sure on this change, it might break some people's code, and if it's not inside an if and not svelte:component
with dynamic this
, it's not true. Suppose you are in strict mode, then you could type the binding variable as let component: Component | undefined
and this breaks for you (null !== undefined).
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, I'll remove it. people using this inside {#if}
will hopefully be aware, and needless strictness over null|undefined
s is annoying
I merged a PR using yours as a base line. Thanks for bringing this up! |
This uses idea from #363, which however didn't work for HTMLElements and was therefore reverted in #402.
The resulting tsx looks like this:
<sveltecomponent this={ComponentType} {...__sveltets_1_empty((data[k] = __sveltets_1_instanceOf(ComponentType) || null))} />
As you can see, the ComponentType needs to be duplicated there1, so this is waiting for Rich-Harris/magic-string#193 to be merged and included in a build.
Edit: why I'm doing this:
As shown in the output in the comment below, if I have a component with exported function
() => string
, it should be perfectly ok to assign this component to a variable expecting a function prop of type(a: number) => string | number
(since it's a more concrete type, TS docs). However, the generated tsx currently requires type equality, so an error is raised. That's correct for bidirectional bindings likebind:value
, but not for bind:this - since that only works bottom up (as far as I'm aware). So I fix that.And the other thing I'm improving is the typecheck - there was none on
<svelte:component bind:this={x}
- this is expressed in the title, but I guess I should learn to document things more explicitelyFootnotes
well, it could be just moved and the
this={}
param removed, but perhaps we'll get some checking for that in the future as well ↩