Svelte (Vite) + Bootstrap 5 + SvelteStrap error: Type 'string' is not assignable to type 'ButtonColor'

Viewed 11

I'm using Svelte (Vite) + Bootstrap 5 + SvelteStrap. My code is the following:

<head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css">
</head>
<script>
    import { Button } from 'sveltestrap';
    let color = "danger";
</script>

<div>
    <Button color="{color}">{color}</Button>
</div>

This works normally on the browser, but VSCode says:

Type 'string' is not assignable to type 'ButtonColor'.

I'm just starting out with Svelte, and I'm trying to modify the standard example on the SvelteStrap website:

<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css">
</head>
<script lang="ts">
  import { Button } from 'sveltestrap';
  const colors: any = [
    'primary',
    'secondary',
    'success',
    'danger',
    'warning',
    'info',
    'light',
    'dark'
  ];
</script>

{#each colors as color}
  <div>
    <Button {color}>{color}</Button>
  </div>
{/each}

Using the standard example, no erros are fired. What am I doing wrong? Why is this happening?

1 Answers

This is a typing issue, the error is generated by TypeScript.

The expected type of the color property is a union type of various string values, but by default an array of string literals will be typed as just string[], so its items will no longer be assignable to a more specific string-literal-based type.

You should be able to use as const here to restrict the type of the array to be literal-based:

const colors = [
    'primary',
    'secondary',
    'success',
    'danger',
    'warning',
    'info',
    'light',
    'dark'
] as const; // <--

This is the full ButtonColor type definition:

declare type ButtonColor =
  | 'primary'
  | 'secondary'
  | 'success'
  | 'danger'
  | 'warning'
  | 'info'
  | 'light'
  | 'dark'
  | 'link';

The type is not exported (though it should be), so it cannot be used directly, but you can extract it from the Button class:

import type { SvelteComponentTyped } from 'svelte';
import type { Button } from 'sveltestrap';

type PropsOf<C> = C extends SvelteComponentTyped<infer Props> ? Props : never;
type ButtonProps = PropsOf<Button>;
type ButtonColor = Exclude<ButtonProps['color'], undefined>;

TS Playground Demo

You could also type your array using this:

const colors: ButtonColor[] = [
    'primary',
    'secondary',
    'success',
    'danger',
    'warning',
    'info',
    'light',
    'dark'
];
Related