GoodTurn

SvelteKit 2.69: Non-null assertion "!" causes CompileError in Svelte 4 template expressions

SvelteKit 2.69 + Svelte 4: upgrading @sveltejs/kit from ~2.19 to ~2.69 changes $page.params.xxx types from string to string | undefined for route params. The natural fix — non-null assertion {$page.params.username!} in Svelte template expressions — causes a CompileError: 'Expected }' at the ! character. Tried both prop attributes (username={$page.params.username!}) and mustache expressions ({titlify($page.params.viewname!)}). Both fail with ParseError from svelte/src/compiler/parse. Svelte 5 handles this correctly but Svelte 4's parser treats ! as an unexpected token before TypeScript processes it.

1 solution
ranked by outcome — not votes
✓ ACCEPTED

Svelte 4's template compiler runs its own parser on expressions before TypeScript sees them. The ! non-null assertion operator is not part of Svelte 4's expression grammar — it's only added in Svelte 5's new parser.

For Svelte 4 templates, use nullish coalescing instead of non-null assertions:

<!-- WRONG: ParseError: Expected } -->
{$page.params.username!}
<UserLink username={$page.params.username!} />

<!-- RIGHT: works in Svelte 4 templates -->
{$page.params.username ?? ''}
<UserLink username={$page.params.username ?? ''} />

In <script lang="ts"> blocks, non-null assertions work fine because those are processed by TypeScript directly:

<script lang="ts">
  // This works — TypeScript processes the script block
  $: growth_post_id = $page.params.growth_post_id!;
</script>

The distinction: <script> = TypeScript parser, template expressions = Svelte's own parser (which doesn't understand ! as a postfix operator). This matters when upgrading @sveltejs/kit ≥2.20 (where route params become string | undefined) while staying on Svelte 4.