svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Svelte 5 $props not working with lang='ts' without types

Open timscodebase opened this issue 1 year ago • 3 comments

Describe the bug

Many of the components for my personal website require the use of prop. This is obviously a basic usage of Svelte and so is TypeScript so I thought it odd when I upgraded to Svelte 5 and none of my components worked when I converted my props to the new runes syntax. I was on a last ditch effort after a long walk that I decided to fix the type errors.

Reproduction

This component is a great example: https://github.com/timscodebase/design-tim/blob/main/src/lib/components/SkillGrid/Skill.svelte

<script lang="ts">
	import { onMount } from 'svelte'
	import { scale } from 'svelte/transition'
	import { Chip, Link } from '$lib'
	import { viewport, slugify } from '$utils'
	import { navColor } from '$stores'
	import type { SkillType } from '$lib/types'

	const { skill, visible } = $props<{ skill: SkillType; visible: boolean }>()
	let isVisible = $state(visible)

	onMount(() => {
		const box = document.querySelector('.outer')
		if (!isVisible && viewport.isIn(box)) {
			isVisible = true
		}

		document.addEventListener(
			'scroll',
			function () {
				if (!isVisible && viewport.isIn(box)) {
					isVisible = true
				}
			},
			{
				passive: true
			}
		)
	})

	function onMouseover() {
		navColor.set(skill.category)
	}
</script>

<div class="outer">
	{#if isVisible}
		<div
			tabindex="0"
			on:touchstart={onMouseover}
			on:mouseover={onMouseover}
			on:focus={onMouseover}
			class={`skill ${skill.category}`}
			in:scale={{ duration: 500 }}
			out:scale={{ duration: 500 }}
		>
			<h3>{skill.name}</h3>

			<p class="info">
				<b class="bold"
					>{skill.yearsExp}
					{parseInt(skill.yearsExp) > 1 ? ` years` : `year`}</b
				>
				<br />{skill.category}
				<br /><b class="bold">{skill.level}</b>
			</p>

			<h4>Used At</h4>
			<ul class="usedAt">
				<!-- alphabetize list -->

				{#each skill.usedAt.sort() as usedAt}
					<Chip liClass={skill.category}>
						<Link href={`/jobs/#${slugify(usedAt)}`}>{usedAt}</Link>
					</Chip>
				{/each}
			</ul>
		</div>
	{/if}
</div>

The above code works.

If you change the prop to:

const { skill, visible } = $props

I get the error below indicating that the props are undefined.

Logs

chunk-O7IYX3P4.js?v=b0604889:690 Uncaught TypeError: Cannot read properties of undefined (reading 'yearsExp')
    at Skill.svelte:43:14
    at chunk-2TIX4LCG.js?v=b0604889:1197:33
    at execute_signal_fn (chunk-O7IYX3P4.js?v=b0604889:570:7)
    at execute_effect (chunk-O7IYX3P4.js?v=b0604889:705:31)
    at schedule_effect (chunk-O7IYX3P4.js?v=b0604889:777:5)
    at internal_create_effect (chunk-O7IYX3P4.js?v=b0604889:1284:5)
    at render_effect (chunk-O7IYX3P4.js?v=b0604889:1360:10)
    at Module.text_effect (chunk-2TIX4LCG.js?v=b0604889:1197:3)
    at Skill.svelte:38:30
    at chunk-2TIX4LCG.js?v=b0604889:1928:9

System Info

ystem:
    OS: macOS 14.4
    CPU: (8) arm64 Apple M1
    Memory: 92.23 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.21 - /opt/homebrew/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 8.14.3 - ~/Library/pnpm/pnpm
    bun: 1.0.25 - ~/.bun/bin/bun
  Browsers:
    Chrome Canary: 123.0.6274.0
    Safari: 17.4
    Safari Technology Preview: 17.4
  npmPackages:
    svelte: 5.0.0-next.37 => 5.0.0-next.37

Severity

blocking an upgrade

timscodebase avatar Feb 01 '24 23:02 timscodebase

const { skill, visible } = $props(), u missing the call

zhihengGet avatar Feb 01 '24 23:02 zhihengGet

I realized I am using $props when I should be using $props()

timscodebase avatar Feb 01 '24 23:02 timscodebase

Re-opening this because I think the compiler should provide a useful error in this situation

Rich-Harris avatar Feb 01 '24 23:02 Rich-Harris