Repository navigation
--tsgo: .svelte files imported through package.json imports (e.g. Kit 3 #lib/*) resolve to the ambient *.svelte shim #3142
Description
Describe the bug
With --tsgo, a .svelte file imported through a package.json imports (subpath import) alias, such as SvelteKit 3's #lib/*, resolves to the ambient declare module "*.svelte" shim instead of the emitted .svelte.ts overlay. Named exports from <script module> then fail with TS2614, and component props become any, so every callback parameter reports TS7006. The same component imported by a relative path in the same file is typed correctly, and the default mode (no --tsgo) reports nothing.
This looks like the package.json#imports counterpart of #2952 (fixed for tsconfig paths in #2955). SvelteKit 3 replaced $lib (a paths alias) with #lib (a subpath import), so every Kit 3 app that imports components as #lib/….svelte hits it. In our app (556 .svelte files, Kit 3.0.0) --tsgo reports 103 false errors and the default mode reports 0.
Reproduction
package.json:
{
"name": "svelte-check-tsgo-subpath-imports",
"private": true,
"type": "module",
"imports": { "#lib/*": "./src/lib/*" },
"devDependencies": {
"svelte": "5.57.1",
"svelte-check": "4.7.6",
"typescript": "npm:@typescript/typescript6@6.0.2",
"@typescript/native": "npm:typescript@7.0.2"
}
}tsconfig.json:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"types": ["svelte"]
},
"include": ["src/**/*.ts", "src/**/*.svelte"]
}src/lib/Counter.svelte:
<script module lang="ts">
export const STEP = 1;
</script>
<script lang="ts">
let { label, onpick }: { label: string; onpick: (value: number) => void } = $props();
</script>
<button onclick={() => onpick(STEP)}>{label}</button>src/App.svelte:
<script lang="ts">
import Counter, { STEP } from "#lib/Counter.svelte";
import Relative, { STEP as RELATIVE_STEP } from "./lib/Counter.svelte";
let total = $state(STEP + RELATIVE_STEP);
</script>
<Counter label="via #lib" onpick={(value) => (total += value)} />
<Relative label="relative" onpick={(value) => (total += value)} />
<p>{total}</p>Then:
$ npx svelte-check --tsconfig ./tsconfig.json
svelte-check found 0 errors and 0 warnings
$ npx svelte-check --tsconfig ./tsconfig.json --tsgo
src/App.svelte:2:21
Error: Module '"*.svelte"' has no exported member 'STEP'. Did you mean to use 'import STEP from "*.svelte"' instead? (ts)
src/App.svelte:7:36
Error: Parameter 'value' implicitly has an 'any' type. (ts)
svelte-check found 2 errors and 0 warnings in 1 file
Both errors are on the #lib import and its usage (lines 2 and 7). The relative import of the same file (lines 3 and 8) is clean.
--tsgo-experimental-api handles this case correctly (0 errors), so only the overlay-tsconfig --tsgo / --incremental path is affected.
Expected behaviour
The same result as the default mode: subpath-import specifiers that map to a .svelte file resolve to its emitted overlay, the way relative and paths-alias specifiers do after #2955.
System Info
- svelte-check 4.7.6, svelte 5.57.1
- typescript 6.0.2 (via
@typescript/typescript6),@typescript/native= typescript 7.0.2 - Node 26.10.0, Linux x64
Which package is the issue about?
svelte-check
Additional Information, eg. Screenshots
From reading incremental.ts, it looks like the overlay tsconfig only rebases compilerOptions.paths (rebasePathsConfig). A package.json imports target such as ./src/lib/* is resolved by TypeScript straight to the source .svelte file, which never matches an emitted .svelte.ts, so resolution falls through to the ambient module.
Activity
jasonlyu123 commentedon Oct 15, 2026
I think we won't fix this. Once content mapper support is out with TypeScript 7.1. The overlay way won't be needed anymore. So it doesn't really make sense to spend the time fixing this at this point.
TheEisbaer commentedon Oct 16, 2026
Another data point, same symptoms with
--incremental(no--tsgo):moduleResolution: "bundler"package.json:"imports": { "#lib/*": "./src/lib/*" }, nokit.aliassvelte-kit sync && svelte-check --tsconfig ./tsconfig.json --incrementalWithout a tsconfig
pathsentry: 18 errors in 9 files. All of them are.sveltefiles imported through#lib/*falling back to the ambient*.svelteshim:Module '"*.svelte"' has no exported member 'PromptFormResult'Parameter 'e' implicitly has an 'any' typeon component callback propsSvelteComponentNo
Cannot find moduleerrors. Adding"paths": { "#lib/*": ["./src/lib/*"] }totsconfig.jsonbrings it to 0 errors, so the overlay picks uppathsbut notimports.Related: Kit's
get_paths(packages/kit/src/core/sync/write_tsconfig/index.js) and the$app/tsconfigdocs say the generatedpathsinclude package.jsonimports, but the code reads onlykit.alias. If it did what the docs say, this workaround wouldn't be needed with--incrementaleither.Since #3142 is marked won't-fix pending TS 7.1, the tsconfig
pathsentry is a working stopgap for anyone else on Kit 3 with--incremental.jasonlyu123 commentedon Oct 16, 2026
I can take a look If anyone can find a fix. Just don't give me 500+ lines of AI generated test script.
build(web): type-check every component on typescript 6
build(web): type-check every component on typescript 6 (#895)
fix(httpapi): describe a plugin's source as a string (#894)