ivanhofer / sveltekit-typescript-showcase

This repository shows how Svelte and SvelteKit work together with TypeScript.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: Typescript narrowing between script and "HTML"

jamesshannon opened this issue · comments

Trying to figure something out and I found your documentation but it doesn't address my question. So I was hoping you could answer it and maybe update the docs.

I'm trying to narrow down a variable. My IDE (VS Code) understands that the variable is narrowed in the script (<script lang="ts">) but not in the "HTML" code outside of the script. Basically, I'm doing this inside of a component:

<script lang="ts">
// creating this as undefined so that the component can be created without passing in partner
export let partner: Partner | undefined = undefined;

if (! partner) {
  partner = new Partner();
}
</script>

<span>{ partner.id }</span>

Inside of the script, after the if block, typescript accurately understands that partner is now Partner.

However, I get an error within the -- partner: Partner | undefined -- 'partner' is possibly 'undefined'.

My expectation is that since Partner has been narrowed at the end of the script block it'll be narrowed within the HTML as well.

Am I doing something wrong? Is there a workaround?

You could create a new issue in the https://github.com/sveltejs/language-tools/ repo.

What I usually do when a type does not match is to create a function that casts the type. SOmething like this:

<script lang="ts">
	export let partner: Partner | undefined = undefined;

	if (!partner) {
		partner = new Partner();
	}

+	const castPartner = (partner: Partner | undefined) => partner as Partner
</script>

-<span>{ partner.id }</span>
+<span>{ castPartner(partner).id }</span>

Or in your specific case you don't need a cast at all:

<script lang="ts">
-	export let partner: Partner | undefined = undefined;
+	export let partner: Partner = new Partner();

-	if (!partner) {
-		partner = new Partner();
-	}
</script>

<span>{ partner.id }</span>

You can also create an internal representation of that param:

<script lang="ts">
	export let partner: Partner | undefined = undefined;

+	$: _partner = partner || new Partner();
</script>

-<span>{ partner.id }</span>
+<span>{ _partner.id }</span>