fix: svelte 5 prop types (#14934)

This commit is contained in:
Antony Faris
2025-12-05 05:05:28 -05:00
committed by GitHub
parent ef53716f93
commit 4264a36571
14 changed files with 131 additions and 7 deletions

View File

@@ -0,0 +1,5 @@
---
'@astrojs/svelte': patch
---
Fixes an issue where Svelte 5 components used in Astro files would not have proper type checking and IntelliSense.

View File

@@ -24,10 +24,12 @@
"./editor": "./dist/editor.cjs",
"./client.js": "./dist/client.svelte.js",
"./server.js": "./dist/server.js",
"./svelte-shims.d.ts": "./svelte-shims.d.ts",
"./package.json": "./package.json"
},
"files": [
"dist"
"dist",
"svelte-shims.d.ts"
],
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && astro-scripts build \"src/editor.cts\" --force-cjs --no-clean-dist && tsc",

View File

@@ -7,12 +7,22 @@ export function toTSX(code: string, className: string): string {
`;
try {
let tsx = svelte2tsx(code, { mode: 'ts' }).code;
tsx = '/// <reference types="svelte2tsx/svelte-shims" />\n' + tsx;
result = tsx.replace(
'export default class extends __sveltets_2_createSvelte2TsxComponent(',
`export default function ${className}__AstroComponent_(_props: typeof Component.props): any {}\nlet Component = `,
);
let tsx = svelte2tsx(code, { mode: 'ts', isTsFile: true }).code;
tsx = "import '@astrojs/svelte/svelte-shims.d.ts';\n" + tsx;
// New svelte2tsx output (Svelte 5)
if (tsx.includes('export default $$Component;')) {
result = tsx.replace(
'export default $$Component;',
`export default function ${className}__AstroComponent_(_props: import('svelte').ComponentProps<typeof $$$$Component>): any {}`,
);
} else {
// Old svelte2tsx output
result = tsx.replace(
'export default class extends __sveltets_2_createSvelte2TsxComponent(',
`export default function ${className}__AstroComponent_(_props: typeof Component.props): any {}\nlet Component = `,
);
}
} catch {
return result;
}

View File

@@ -0,0 +1 @@
import 'svelte2tsx/svelte-shims-v4';

View File

@@ -0,0 +1,18 @@
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';
import { cli } from '../../../astro/test/test-utils.js';
describe('Svelte Check', () => {
it('should fail check on type error', async () => {
const root = fileURLToPath(new URL('./fixtures/prop-types/', import.meta.url));
const { getResult } = cli('check', '--root', root);
const { exitCode, stdout } = await getResult();
assert.equal(exitCode, 1, 'Expected check to fail (exit code 1)');
assert.ok(
stdout.includes(`Type 'string' is not assignable to type 'number'`),
'Expected specific type error message',
);
});
});

View File

@@ -0,0 +1,13 @@
<script lang="ts">
interface Props {
name: string;
age?: number;
bold?: boolean;
}
let { name, age = 0, bold = false }: Props = $props();
</script>
<p class:bold={bold}>
Hello {name}, you are {age} years old.
</p>

View File

@@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}

View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
export default defineConfig({
srcDir: './types',
integrations: [svelte()]
});

View File

@@ -0,0 +1,16 @@
{
"name": "svelte-prop-types",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/svelte": "^7.2.2",
"astro": "^5.16.0",
"svelte": "^5.43.14"
}
}

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}

View File

@@ -0,0 +1,13 @@
<script lang="ts">
interface Props {
name: string;
age?: number;
bold?: boolean;
}
let { name, age = 0, bold = false }: Props = $props();
</script>
<p class:bold={bold}>
Hello {name}, you are {age} years old.
</p>

View File

@@ -0,0 +1,16 @@
---
import PropTypes from './PropTypes.svelte';
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro</h1>
<PropTypes name="Test" age="invalid" bold />
</body>
</html>

12
pnpm-lock.yaml generated
View File

@@ -6024,6 +6024,18 @@ importers:
specifier: ^5.43.14
version: 5.43.14
packages/integrations/svelte/test/fixtures/prop-types:
dependencies:
'@astrojs/svelte':
specifier: ^7.2.2
version: link:../../..
astro:
specifier: ^5.16.0
version: link:../../../../../astro
svelte:
specifier: ^5.43.14
version: 5.43.14
packages/integrations/vercel:
dependencies:
'@astrojs/internal-helpers':