Skip to main content

TypeScript

Vous pouvez utiliser TypeScript dans vos composants Svelte. Les extensions d’IDE comme l’extension VS Code de Svelte vous permettent de visualiser les erreurs directement dans votre éditeur, et svelte-check fait la même chose en ligne de commande, ce que vous pouvez utiliser dans votre CI.

<script lang="ts">

Pour utiliser TypeScript dans vos composants Svelte, ajoutez lang="ts" à vos balises script :

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

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

<button onclick={(e: Event) => greet(e.target.innerText)}>
	{name as string}
</button>

Faire cela vous permet d’utiliser les fonctionnalités de type de TypeScript, c’est-à-dire toutes les fonctionnalités qui disparaissent lorsque vous transpilez vers JavaScript, comme les annotations de type ou les déclarations d’interface. Les fonctionnalités qui demandent au compilateur TypeScript de générer du code ne sont pas supportées. Ceci inclut :

  • l’utilisation d’enums
  • l’utilisation des modificateurs private, protected ou public dans les fonctions de constructeur couplée à l’initialisation de propriétés.
  • l’utilisation de fonctionnalités qui ne sont pas encore intégrées au standard ECMASCript (c-à-d qui ne sont pas en stage 4 du processus TC39), et donc pas encore implémentées dans Acorn, le parser que nous utilisons pour interpréter JavaScript.

Si vous souhaitez utiliser une de ces fonctionnalités, vous aurez besoin de mettre en place un préprocesseur de script.

Mise en place de préprocesseurs

Pour utiliser les fonctionnalités TypeScript non restreintes au type au sein de vos composants, vous aurez besoin d’ajouter un préprocesseur qui va transformer TypeScript en JavaScript.

Using Vite

If you’re using SvelteKit, or Vite without SvelteKit, you can use vitePreprocess from @sveltejs/vite-plugin-svelte in your config file:

svelte.config
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

const config = {
	// Notez le `{ script: true }` additionnel
	preprocess: vitePreprocess({ script: true })
};

export default config;

Using other build tools

Si vous utilisez plutôt des outils comme Rollup (via rollup-plugin-svelte) ou Webpack (via svelte-loader), installez typescript et svelte-preprocess et ajoutez le préprocesseur à la configuration de plugin. Consultez les fichiers READMEs des plugins concernés pour plus d’infos.

Si vous commencez un nouveau projet, nous recommandons plutôt d’utiliser SvelteKit ou Vite.

Paramètres de tsconfig.json

Lorsque vous utilisez TypeScript, assurez-vous que votre fichier tsconfig.json soit correctement défini.

  • Utilisez une target qui soit au moins ES2015, ou bien une target d’au moins ES2015 afin que les classes ne soient pas compilées en tant que fonctions
  • Mettez verbatimModuleSyntax à true pour conserver les imports tels quels
  • Mettez isolatedModules à true pour que chaque fichier soit considéré en isolation. TypeScript a quelques fonctionnalités qui nécessitent une analyse croisée de fichiers ainsi qu’une compilation, ce que le compilateur de Svelte et des outils comme Vite ne font pas.

Typer les $props

Vous pouvez typer les $props comme un objet normal qui possèderait certaines propriétés.

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

	interface Props {
		propRequise: number;
		propOptionnelle?: boolean;
		snippetAvecUnArgumentString: Snippet<[string]>;
		gestionnaireEvenement: (arg: string) => void;
		[key: string]: unknown;
	}

	let {
		requiredProperty,
		optionalProperty,
		snippetWithStringArgument,
		eventHandler,
		...everythingElse
	}: Props = $props();
</script>

<button onclick={() => eventHandler('bouton cliqué')}>
	{@render snippetWithStringArgument('coucou')}
</button>

$props génériques

Les composants peuvent déclarer des relations génériques entre leurs propriétés. Vous pouvez avoir par exemple un composant de liste qui reçoit en props une liste d’éléments ainsi qu’un callback ayant pour argument un élément de la liste. Pour déclarer que la propriété items et le callback select traitent de données du même type, ajoutez l’attribut generics à la balise script :

<script lang="ts" generics="Item extends { text: string }">
	interface Props {
		items: Item[];
		select(item: Item): void;
	}

	let { items, select }: Props = $props();
</script>

{#each items as item}
	<button onclick={() => select(item)}>
		{item.text}
	</button>
{/each}

Le contenu de generics est ce que vous mettriez entre les chevrons <...> d’une fonction générique. Autrement dit, vous pouvez utiliser plusieurs génériques, extends, ainsi que des types par défaut.

Typer des composants haut-niveau

Si vous construisez un composant qui englobe un élément natif, vous pourriez vouloir exposer tous les attributs de l’élément sous-jacent à l’utilisateur. Dans ce cas, utilisez (ou héritez) l’une des interfaces fournies par svelte/elements. Voici un exemple pour un composant Button :

<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';

	let { children, ...rest }: HTMLButtonAttributes = $props();
</script>

<button {...rest}>
	{@render children?.()}
</button>

Tous les éléments n’ont pas nécessairement de définition de type dédiée. Pour ceux qui n’en ont pas, utilisez SvelteHTMLElements :

<script lang="ts">
	import type { SvelteHTMLElements } from 'svelte/elements';

	let { children, ...rest }: SvelteHTMLElements['div'] = $props();
</script>

<div {...rest}>
	{@render children?.()}
</div>

Typer $state

Vous pouvez typer $state comme toute autre variable.

let count: number = $state(0);

Si vous ne fournissez pas de valeur initiale à $state, son type sera en partie undefined.

// Error: Type 'number | undefined' is not assignable to type 'number'
let count: number = $state();

Vous pouvez fournir le type directement en tant que paramètre générique pour gérer ce cas de manière plus sécurisée. TypeScript va inférer que la variable peut être number | undefined.

let count = $state<number>();

Si vous savez que la variable sera définie avant que vous vous en serviez, castez cette variable avec as. Ceci est particulièrement utile lorsque vous utilisez des classes :

class Counter {
	count = $state() as number;
	constructor(initial: number) {
		this.count = initial;
	}
}

Le type Component

Les composants Svelte sont de type Component. Vous pouvez vous en servir, ainsi que les types associés, pour exprimer toute une variété de contraintes.

Cela sert notamment avec les composant dynamiques pour restreindre quels sont les composants qui peuvent leur être fournis :

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

	interface Props {
		// seuls les composants qui ont au plus la propriété "prop"
		// peuvent être fournis
		ComposantDynamique: Component<{ prop: string }>;
	}

	let { ComposantDynamique }: Props = $props();
</script>

<ComposantDynamique prop="foo" />
Legacy mode

En Svelte 4, les composants étaient de type SvelteComponent

Pour extraire le type des propriétés d’un composant, utilisez ComponentProps.

import type { Component, ComponentProps } from 'svelte';
import MonComposant from './MonComposant.svelte';

function withProps<TComponent extends Component<any>>(
	component: TComponent,
	props: ComponentProps<TComponent>
) {}

// Affiche une erreur si le deuxième argument n'a pas les props attendues
// par le composant en premier argument
withProps(MonComposant, { foo: 'bar' });

Pour déclarer qu’une variable attend le constructeur ou une instance d’un composant :

<script lang="ts">
	import MyComponent from './MyComponent.svelte';

	let componentConstructor: typeof MyComponent = MyComponent;
	let componentInstance: MyComponent;
</script>

<MyComponent bind:this={componentInstance} />

Améliorer les types natifs du DOM

Svelte fait son maximum pour fournir les types de tous les éléments du DOM existants. Il se peut que parfois, vous vouliez utiliser des attributs expérimentaux ou des évènements personnalisés venant d’une action. Dans ces cas-là, TypeScript va lever une erreur, vous disant qu’il ne connait pas ces types. S’il s’agit d’attributs ou d’évènements standards non-expérimentaux, cela peut simplement être un oubli dans nos définitions de types HTML. Dans ce cas, vous pouvez ouvrir une issue et/ou une PR pour corriger le problème.

S’il s’agit d’un évènement/attribut expérimental, vous pouvez améliorer le typage en augmentant le module svelte/elements de cette manière :

additional-svelte-typings.d
import { HTMLButtonAttributes } from 'svelte/elements';

declare module 'svelte/elements' {
	// ajoute un nouvel élément
	export interface SvelteHTMLElements {
		'bouton-perso': HTMLButtonAttributes;
	}

	// ajout un nouvel attribut global qui est disponible sur tous les éléments HTML
	export interface HTMLAttributes<T> {
		globalattribute?: string;
	}

	// ajoute un nouvel attribut pour les éléments bouton
	export interface HTMLButtonAttributes {
		attributtresexperimental?: string;
	}
}

export {}; // assure que ceci n'est pas un module ambiant, sans quoi les types seraient écrasés

Assurez-vous ensuite que le fichier .d.ts est référencé dans votre fichier tsconfig.json. S’il contient quelque chose comme "include": ["src/**/*"] et que votre fichier .d.ts se trouve dans src, cela devrait fonctionner. Vous aurez peut-être besoin de recharger pour que les changements aient de l’effet.

Modifier cette page sur Github llms.txt

précédent suivant