-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
svelte accidentally contains two incompatible Snippet types that cause type checking failures #15182
Comments
I think we need a reproduction for this... who's gonna import a type from node modules? I understand what you are saying but I don't see how this can be an issue in a real project. |
The repro is obviously contrived to show the result - in previous issues, people assumed it was the setup that was broken and causing a buggy error message. In this case - as i said, it happens in my real project, which does nothing abnormal (as far as i know). I have shared @dberlin/modeler-svelteflow with you privately because it's very hard to minimize the code but keep the bug, and it has code i can't make public (ie pro examples from xyflow). It normally requires the migrate/svelte5 branch of @xyflow/svelte, which makes it annoying to just build. So it fails even without all the packages installed. svelte-check does not support the equivalent of generateTrace that tsc/tsserver has to trace import and type resolution, and adding generateTrace to the tsconfig doesn't work for svelte-check, so it's hard to trace the imports to see what is going on. I spent a bit of time seeing if i could hack the tracing support into svelte-check, but no luck - it doesn't appear to be exported from the typescript apis svelte-check uses in a way that makes this easy. That would have been really nice, as it would likely immediately pinpoint how things are breaking. I also spent a bit of time trying to see what is going on in the svelte-language-server, but i ran out of time. there are a lot of suspects to run down - it has it's own module resolution mechanism and caching, the generated index.d.ts files it use force-import types/index.js, etc. If i get more time in the next few days i'll try to continue chasing it down. As for other real world examples - besides the bug reports on the issue tracker, there are other edge cases that will fail, but not sure if anyone cares. For example - any case where you use a library that vendors svelte 5 or it's types, the snippet types will be incompatible with your non-vendored one. So say a component library that vendors svelte types will not be able to render snippets you pass it from your non-vendored copy. I will say that i'm also happy to send a PR to just fix this issue. It should cause no harm elsewhere, and they are definitely different types. |
It is real...if people were importing the unique symbol from that specific file. That's what I'm saying, obviously you can cause the error but is it really possible without this weird setup?
Which is exactly why we need a minimal repro: as far as you know you are not doing anything weird...but maybe you are and we would chase a bug that is not there.
I'll try to take a look if I have time but I can't guarantee...I can't stress enough how important is that the reproduction is minimal. Before being able to figure out if you are doing something wrong I have to explore your whole project which also involves libraries for which I might not even have knowledge of.
This feels weird to me: svelte library generally are not bundled and the imports are resolved within the user project |
"It is real...if people were importing the unique symbol from that specific file. That's what I'm saying, obviously you can cause the error but is it really possible without this weird setup?" Yes, i've given you one example, #13760 has another example. I will say i'm a bit confused at what you want - do we want a real world example or a minimal one? Those are very different things. I thought you wanted a real world one, so i gave you a real world one. It sounds like what you really want may be an idiomatic minimal one? In any case, hopefully, in the interest of moving forward, I tracked down why it happens, at least in this case. I got a little more time to instrument the module loading in the language service. The module cache in svelte-language-service is not always resolving the 'svelte' module to the same filename, depending on the paths involved and order of files loaded (I didn't dive too deep on the exact cause of resolution order change). Cache misses then cause it to two load copies of types. So in one load order, it is resolving the svelte module to a global cache: Setting module svelte, containing file /Users/dannyb/sources/modeler-svelteflow/node_modules/@xyflow-svelte/packages/svelte/dist/lib/plugins/Controls/types.d.ts, resolved filename is But later: Checking for module svelte, containing file /Users/dannyb/sources/modeler-svelteflow/src/routes/apps/+layout.svelte, result is miss In a different file load order, it will do the second, then the first becomes a cache hit instead of a miss, and you get no error. Note: In this particular case, these are actually the same file (not like content wise, but literally, there are not two files on the filesystem), but it is loading a new instance of the module anyway, causing a new instance of the unique symbol to occur. So in this particular case, it is loading the types file twice, changing the definition of SnippetReturn as that happens. But if this was not the case, it looks like you'd end up with two different files loaded. I can also get it to load the src version and the types version ,through messing with file import order and some of the bare import statements that are around. Hopefully this is enough for you to go on. |
Did you link to the wrong PR? I saw no error there.
Yeah a minimal example that doesn't involve you importing from node modules. From the resto of your exploration it seems is more of a language tools issue than a svelte one. |
Sorry, #13670. There are others as well. As for the rest - what's here is clearly a bug, whether you decide to fix it or not. I'll respect that. But in the end, it is your decision to make. |
What? I never said we should close this... I'm trying to understand the issue so that it can be fixed in the right way. Saying "if the user imports the type from node modules it will trigger the issue" it's weird because none will ever do that. I'm asking for a minimal reproduction so that if we understand what really cause the error we can fix it there. That's it. |
That's not what I said, anywhere, so not sure why you put that in quotes. In fact, i specifically said that people in the past, like in #13670, simply dismissed it as not a real error. I also said i will give you a a very small reproduction to show you it's a real error. Which i did. I specifically said the same error occurs in my real world project, and pasted the error message right after the example. Then after you asked for the real world project, i gave you that too. What i've actually said other than that, is that it doesn't matter how it happens. It only matters that multiple instances of either type occur. We are clearly not communicating effectively to say the least, and this seems highly unproductive at this point, so i'm going to bow out of this bug. |
What I meant with my interaction is that saying "yeah previously was real" without providing a series of step to reproduce is not helpful to understand the error. Neither is saying I should import from node modules to reproduce. That's why I asked you for a real minimal reproduction which you said you could provide so I was waiting for you to do it. Since this error can happen in situations that are not bugs it's important to get a reproduction not just say "it can happen". I said I will take a look at your non minimal reproduction but I don't know when I can get to it and if you provide a minimal one I'll take a look immediately.
You described how it could happen...what I'm looking at is a series of step I can follow to make it happen which I've yet to see and that's all I'm asking for. |
It's kinda compicated to replicate... We have a separate project for components and other stuff that being published on private npm. |
So you are getting that error in the "components project" or where you use them? |
Only where we are using them. |
And how you get access to prefix? Is a snippet argument? Also I can't see how you are using it. If it's a snippet shouldn't it be rendered instead of just used as an expression? |
OH mb, nvm, we are getting that error on both projects... |
Thanks...could you please copy your |
Yeah, just in case i'll copy them "as is" without removing stuff
import type { InputProps } from "../types.js";
declare const Input: import("svelte").Component<InputProps, {}, "value">;
type Input = ReturnType<typeof Input>;
export default Input;
import type { Snippet } from "svelte";
import type { HTMLAttributes, HTMLInputTypeAttribute } from "svelte/elements";
import type { inputSizes } from "./consts.js";
export type InputSize = (typeof inputSizes)[number];
export type InputProps = {
value?: string;
error?: string;
placeholder?: string;
isSuccess?: boolean;
size: InputSize;
className?: string;
disabled?: boolean;
prefix?: Snippet;
suffix?: Snippet;
type?: HTMLInputTypeAttribute;
name?: string;
} & HTMLAttributes<HTMLInputElement>;
export type InputErrorLabelProps = {
value?: string | number;
error?: string;
className?: string;
};
export type InputPlaceholderLabelProps = {
value?: string | number;
placeholder?: string;
size: InputSize;
className?: string;
};
export declare const inputSizes: readonly ["large", "medium", "small"]; |
Hey, @paoloricciuti , sry for pinging, but I actually found what was causing problem for me: export type InputProps = {
prefix?: Snippet
} & HTMLAttributes<HTMLInputElement> Removing |
Uh this together with @dberlin explanation might be a very good hint...maybe the html attributes type is importing from the different symbol? I can't explore this right now but I'll try tomorrow |
I just found out that I apologize that I may have led your thoughts in the wrong direction in solving this issue... I've just never seen or heard of its existence... |
No worries...I wonder if it could be a similar problem for @dberlin |
@dberlin i went take a look at your code but i don't have access anymore, if you could invite me again i have a bit of time now |
I see that this has had a long conversation. I won't butt-in, but I'll mention that I opened #13759 some time ago regarding problems with the Snippet type. Mine has a simple code, I would say. |
Nice I'll try to take a look |
Wow.. I am not alone. and here is the code my component.
{#snippet sliderTopTitle({ direction, title }: TSliderTopTitleParam)}
<div class="title-wrapper relative h-[100px] lg:h-[300px]">
<h1
class="text-h3 lg:text-h2 2xl:text-h1 absolute top-1/2 w-full -translate-y-1/2 {direction === 'left'
? 'text-shark-500 right-10 text-end'
: direction === 'right'
? 'text-shark-500 left-10 text-start'
: 'text-center'}"
>
{@html title}
</h1>
</div>
{/snippet}
<!--Passing snippet to component -->
<section class="">
<div class="ml:h-[1040px]">
<swiper-container pagination="true" pagination-clickable={true} class="big-slider-container ml:h-[1040px]">
<swiper-slide>
<div class="container h-full">
<BigSliderSlide1 {sliderTopTitle} />
</div>
</swiper-slide>
</swiper-container>
</div>
</section>
let {
sliderTopTitle
}: {
sliderTopTitle: Snippet<[TSliderTopTitleParam]>;
} = $props(); I got same issue a month ago. but random work arround did solve it. most probably its a dependency mismatch issue. My Dependencies "@eslint/compat": "^1.2.5",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/kit": "^2.17.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.0.3",
"dayjs": "^1.11.13",
"eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.46.1",
"globals": "^15.14.0",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"sass": "^1.83.4",
"svelte": "^5.19.8",
"svelte-check": "^4.1.4",
"tailwindcss": "^4.0.3",
"typescript": "^5.7.2",
"typescript-eslint": "^8.19.0",
"vite": "^6.0.11"
|
Describe the bug
The use of unique symbol as the type of SnippetReturn means that every instance refers to a unique symbol. They are not structurally compatible with each other (unlike basically everything else in typescript)
As such, you have to use typeof on them to get a reference to the same unique symbol.
Which svelte does. Or tries to.
Unfortunately, however, it contains two different instances of the SnippetReturn symbol - one in
src/index.d.ts
, and one intypes/index.d.ts
.Both contain
const SnippetReturn: unique symbol
(of some form), which means both create different unique symbolsIn turn, the Snippet types that exist in each file now have different return values, even though they are typeof'ing that symbol, and because of how unique symbols work, those return values are incompatible with each other.
This causes issues that pop up occasionally on the issue tracker such as #13670.
The above is the cause of this issue (and a few others).
The solution, AFAIK, is to share the
typeof (unique symbol)
between both files, by placing it in a third, so there is only one unique symbol.(I say typeof because as per above, only the typeof will give you the same reference to the unique symbol, so you can't just share the unique symbol, you have to share the typeof)
Reproduction
Just to remove svelte components entirely, i'll use a
.ts
file repro.Place the following in a .ts file in a svelte project (obviously, modify the node_modules path to be correct for your project).
You will receive the following error:
It is correct - the types are in fact unrelated. The strings about
@render
are a red herring they are just part of the type name in the file.The complaint that the different unique symbols aren't compatible is the real complaint.
Now, i will say, while it is easy to reproduce a failure and show it's broken - it is hard to track down the exact circumstances under which both end up getting into the picture.
But it's definitely the same failure in the real world (and in the issues i can find on the issue tracker).
In the real world I have a failing treeview where the render is in a child component (treeitem), the snippet is in the parent component (treeview), and the typecheck failure is in the parent - this is the output of svelte check:
If i remove the snippet related declarations from
types/index.d.ts
, it causes the typecheck failure to go away. So they are definitely getting imported into the language server, and svelte check.In any case, all of this is somewhat moot - i'm just recording it in case it's ever useful for some other bug later. It should hopefully be obvious this is broken, and there is a hopefully easy fix the overall issue - share the
typeof <unique symbol>
between the two files so they are the same unique symbol.I also am going to go over to the typescript repo and file a bug that they should give the unique symbols context info or something in the error messages - so that it is obvious they are not the same.
Logs
System Info
Severity
annoyance
The text was updated successfully, but these errors were encountered: