Skip to main content

Divers

TypeScript

Modifier cette page sur Github

Vous pouvez utiliser TypeScript dans vos composants. Des extensions d'IDE comme l'extension Svelte VSCode vous aideront à voir et corriger les erreurs directement dans votre éditeur, et svelte-check fera la même chose en ligne de commande, que vous pouvez ajouter à votre chaîne d'intégration continue.

Mise en place

Pour utiliser TypeScript dans vos composants Svelte, vous devez ajouter un préprocesseur qui compilera le code TypeScript en JavaScript.

Utiliser SvelteKit ou Vite

La façon la plus simple de démarrer avec Typescript est de créer un nouveau projet en tapant : npm create svelte@latest, en suivant les propositions et en choisissant l'option TypeScript.

svelte.config.js
ts
import { vitePreprocess } from '@sveltejs/kit/vite';
 
const config = {
preprocess: vitePreprocess()
};
 
export default config;

Si vous n'avez pas besoin ou ne souhaitez pas de toutes les fonctionnalités de SvelteKit, vous pouvez démarrer un projet Svelte avec Vite en tapant : npm create vite@latest et en choisissant l'option svelte-ts.

svelte.config.js
ts
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
 
const config = {
preprocess: vitePreprocess()
};
 
export default config;

Dans les deux cas, un fichier svelte.config.js avec vitePreprocess sera ajouté. Vite et SvelteKit liront ce fichier de configuration.

Autres outils de compilation

Si vous utilisez d'autres outils comme Rollup ou Webpack, installez leurs plugins Svelte respectifs. Pour Rollup, il s'agit de rollup-plugin-svelte et pour Webpack, c'est svelte-loader. Dans les deux cas, vous devez installer typescript et svelte-preprocess et ajouter le préprocesseur à la configuration du plugin (voir les documentations respectives). Si vous démarrez un nouveau projet, vous pouvez utiliser le template rollup ou le template webpack pour configurer votre projet.

Si vous démarrez un nouveau projet, nous vous recommandons plutôt d'utiliser SvelteKit ou Vite.

<script lang="ts">

Pour utiliser TypeScript dans vos composants Svelte, ajoutez lang="ts" au tag script :

<script lang="ts">
  let name: string = 'world';

  function greet(name: string) {
    alert(`Hello, ${name}!`);
  }
</script>

Props

Les props peuvent directement être typées sur l'instruction export let :

<script lang="ts">
  export let name: string;
</script>

Slots

Les slots et les types de leurs props sont déduits des types des props qui leurs sont passées :

<script lang="ts">
  export let name: string;
</script>

<slot {name} />

<!-- Ailleurs -->
<Comp let:name>
  <!--    ^ Déduit comme string -->
  {name}
</Comp>

Events

Les événements peuvent être typés avec createEventDispatcher :

<script lang="ts">
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher<{
    event: null; // n'accepte pas d'argument
    click: string; // contient obligatoirement une string
    type: string | null; // peut contenir une string ou être non défini
  }>();

  function handleClick() {
    dispatch('event');
    dispatch('click', 'Salut');
  }

  function handleType() {
    dispatch('event');
    dispatch('type', Math.random() > 0.5 ? 'tout le monde' : null);
  }
</script>

<button on:click={handleClick} on:keydown={handleType}>Clic</button>

Surcharge des types de DOM natifs

Svelte fournit des types aussi proche que possible pour chaque élément HTML du DOM qui existe. Parfois, vous voudrez utiliser des attributs expérimentaux ou des événements personnalisés. Dans ces cas, TypeScript lèvera une erreur de type, en indiquant qu'il ne connaît pas ces types. S'il s'agit d'un attribut ou événement standard et non expérimental, il se peut tout à fait que ce soit un type manquant dans le typage HTML de Svelte. Dans ce cas, vous êtes invité•e à ouvrir une issue ou une PR pour le corriger.

S'il s'agit d'un attribut ou d'un événement expérimental ou personnalisé, vous pouvez étendre le typage comme suit :

ts
/// fichier: additional-svelte-typings.d.ts
declare namespace svelteHTML {
// extension de type pour un élément
interface IntrinsicElements {
'my-custom-element': { someattribute: string; 'on:event': (e: CustomEvent<any>) => void };
}
// extension de type pour un attribut
interface HTMLAttributes<T> {
// Si vous voulez utiliser on:beforeinstallprompt
'on:beforeinstallprompt'?: (event: any) => any;
// Si vous voulez utiliser myCustomAttribute={..} (note: tout en minuscule)
mycustomattribute?: any; // Vous pouvez remplacer any par quelque chose de plus précis si vous le souhaitez
}
}

Ensuite, assurez vous que les fichiers d.ts soient référencés dans tsconfig.json. Si vous lisez quelque chose comme : "include": ["src/**/*"] et vos fichiers d.ts sont dans votre dossier src, ça devrait marcher. Vous devrez peut-être relancer votre serveur pour que le changement prenne effet.

Types avancés expérimentaux

Quelques fonctionnalités sont manquantes pour bénéficier de tous les avantages de TypeScript dans des cas plus avancés, comme pour typer qu'un composant étend une interface, pour typer les slots ou pour utiliser des génériques. Tout ceci est rendu possible en utilisant des fonctionnalités expérimentales avancées. Voir la RFC pour savoir comment définir de tels typages.

Cette API est expérimentale et peut changer à tout moment.

Limitations

Pas de TypeScript dans le code HTML

Vous ne pouvez pas utiliser explicitement TypeScript dans les templates HTML. Par exemple, l'exemple suivant n'est pas possible :

<script lang="ts">
  let count = 10;
</script>

<h1>Count as string: {count as string}!</h1> <!-- ❌ Ne fonctionne pas -->
{#if count > 4}
  {@const countString: string = count} <!-- ❌ Ne fonctionne pas -->
  {countString}
{/if}

Déclarations réactives

Vous ne pouvez pas typer les déclarations réactives avec TypeScript de la manière dont vous typeriez une variable. Par exemple, le code suivant ne fonctionne pas :

<script lang="ts">
  let count = 0;

  $: doubled: number = count * 2; // ❌ Ne fonctionne pas
</script>

Vous ne pouvez pas utiliser : TYPE car cela résulte en une syntaxe invalide. À la place, vous pouvez déplacer le typage sur une instruction let juste au dessus :

<script lang="ts">
  let count = 0;

  let doubled: number;
  $: doubled = count * 2;
</script>

Types

ComponentConstructorOptions

ts
interface ComponentConstructorOptions<
Props extends Record<string, any> = Record<string, any>
> {}
ts
target: Element | Document | ShadowRoot;
ts
anchor?: Element;
ts
props?: Props;
ts
context?: Map<any, any>;
ts
hydrate?: boolean;
ts
intro?: boolean;
ts
$$inline?: boolean;

ComponentEvents

Type utile pour obtenir les évènements qu'un composant attend. Exemple :

<script lang="ts">
   import type { ComponentEvents } from 'svelte';
   import Component from './Component.svelte';

   function handleCloseEvent(event: ComponentEvents<Component>['close']) {
    console.log(event.detail);
   }
</script>

<Component on:close={handleCloseEvent} />
ts
type ComponentEvents<Component extends SvelteComponent_1> =
Component extends SvelteComponent<any, infer Events>
? Events
: never;

ComponentProps

Type utile pour obtenir les props qu'un composant attend. Exemple :

<script lang="ts">
  import type { ComponentProps } from 'svelte';
  import Component from './Component.svelte';

  const props: ComponentProps<Component> = { foo: 'bar' }; // Errors if these aren't the correct props
</script>
ts
type ComponentProps<Component extends SvelteComponent_1> =
Component extends SvelteComponent<infer Props>
? Props
: never;

ComponentType

Type utile pour obtenir le type d'un composant Svelte. Pratique par exemple lorsqu'on utilise les composants dynamiques avec <svelte:component>.

Exemple:

<script lang="ts">
  import type { ComponentType, SvelteComponent } from 'svelte';
  import Component1 from './Component1.svelte';
  import Component2 from './Component2.svelte';

  const component: ComponentType = someLogic() ? Component1 : Component2;
  const componentOfCertainSubType: ComponentType<SvelteComponent<{ needsThisProp: string }>> = someLogic() ? Component1 : Component2;
</script>

<svelte:component this={component} />
<svelte:component this={componentOfCertainSubType} needsThisProp="hello" />
ts
type ComponentType<
Component extends SvelteComponent = SvelteComponent
> = (new (
Component extends SvelteComponent<infer Props>
? Props
: Record<string, any>
>
) => Component) & {
/** La version "web component" du composant. Seulement présent si compilé avec l'option `customElement` */
element?: typeof HTMLElement;
};

SvelteComponent

Classe de base pour les composants Svelte avec quelques améliorations mineures. Utilisé lorsque dev=true.

Peut être utilisé pour créer des composants Svelte fortement typés.

Exemple :

Vous avez une librairie de composants sur npm appelée component-library, depuis laquelle vous exportez un composant appelé MyComponent. Pour les personnes qui utilisent Svelte avec Typescript, vous voulez fournir du typage. Vous créez donc un index.d.ts :

ts
import { SvelteComponent } from "svelte";
export class MyComponent extends SvelteComponent<{foo: string}> {}

Typer ceci permet aux IDEs comme VS Code qui ont l'extension Svelte de fournir de l'Intellisense, et vous pouvez alors utiliser le composant de cette manière dans un fichier Svelte avec Typescript :

<script lang="ts">
  import { MyComponent } from "component-library";
</script>
<MyComponent foo={'bar'} />
ts
Props extends Record<string, any> = any,
Events extends Record<string, any> = any,
Slots extends Record<string, any> = any
> extends SvelteComponent_1<Props, Events> {}
ts
[prop: string]: any;
ts
constructor(options: ComponentConstructorOptions<Props>);
ts
$capture_state(): void;
ts
$inject_state(): void;

SvelteComponentTyped

Utilisez plutôt SvelteComponent. Voir la PR plus d'informations : https://github.com/sveltejs/svelte/pull/8512

ts
class SvelteComponentTyped<
Props extends Record<string, any> = any,
Events extends Record<string, any> = any,
Slots extends Record<string, any> = any
> extends SvelteComponent<Props, Events, Slots> {}