Fred Hors
Fred Hors

Reputation: 4116

Svelte 3, why cannot access this javascript object property if I use reactive statement?

I'm using this code with Svelte 3:

REPL: https://svelte.dev/repl/bf73fffc1b9442dfbcd492eaa9c048e1?version=3.35.0

<script lang="ts">
  const players = {
    men: {
      john: "high",
      bob: "low",
    },
  };

  // const player = "bob"
  $: player = "bob";

  const test = players.men[player];

  console.log(test); //prints undefined
</script>

{player} //bob
{test} //undefined

Typescript even tells me this:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ john: string; bob: string; }'.
  No index signature with a parameter of type 'string' was found on type '{ john: string; bob: string; }'.ts(7053)

If I use const player = "bob" it works!

Why?

Upvotes: 0

Views: 829

Answers (1)

Jared Smith
Jared Smith

Reputation: 21926

You can't use a random string to access an object safely, which is why the compiler complains. The reason it doesn't complain when you use const is that a constant string literal is known at compile time, and it can't change at runtime, so the compiler knows it's safe. There are a few ways around this, but the easiest (N.B. not safest) way is a cast:

  const players = {
    men: {
      john: "high",
      bob: "low",
    },
  };

  // const player = "bob"
  let player = "bob";

  const test = players.men[player as keyof typeof players.men];

There may also exist a safer way to do this with the Svelte thing you are trying to use, typically when writing this sort of thing in TS I will use string literals or an enum to have the compiler ensure I'm not getting an unexpected undefined:

enum Males {
  JOHN = "john",
  BOB = "bob"
}

const players: {
  men: {
    [key in Males]: string;
  }
} = {
  men: {
    john: "high",
    bob: "low",
  },
};

const test2 = players.men[Males.JOHN];

Playground

Upvotes: 2

Related Questions