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.

Depuis Svelte version 4.2 / svelte-check version 3.5 / l'extension VSCode version 107.10.0, vous pouvez aussi déclarer les types en étendant le module svelte/elements comme ceci :

additional-svelte-typings.d.ts
ts
import { HTMLButtonAttributes } from 'svelte/elements';
declare module 'svelte/elements' {
export interface SvelteHTMLElements {
'custom-button': HTMLButtonAttributes;
}
// permet un contrôle plus fin sur l'élément auquel vous ajoutez les types
export interface HTMLButtonAttributes {
veryexperimentalattribute?: string;
}
}
export {}; // assure que ceci n'est pas un module "ambiant", sinon les types seront écrasés au lieu d'être augmentés

Typings 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

Convenience type to get the events the given component expects. Example:

<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

Convenience type to get the props the given component expects. Example:

<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

Convenience type to get the type of a Svelte component. Useful for example in combination with dynamic components using <svelte:component>.

Example:

<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 (
options: ComponentConstructorOptions<
Component extends SvelteComponent<infer Props>
? Props
: Record<string, any>
>
) => Component) & {
/** The custom element version of the component. Only present if compiled with the `customElement` compiler option */
element?: typeof HTMLElement;
};

SvelteComponent

Base class for Svelte components with some minor dev-enhancements. Used when dev=true.

Can be used to create strongly typed Svelte components.

Example:

You have component library on npm called component-library, from which you export a component called MyComponent. For Svelte+TypeScript users, you want to provide typings. Therefore you create a index.d.ts:

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

Typing this makes it possible for IDEs like VS Code with the Svelte extension to provide intellisense and to use the component like this in a Svelte file with TypeScript:

<script lang="ts">
	import { MyComponent } from "component-library";
</script>
<MyComponent foo={'bar'} />
ts
class SvelteComponent<
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

Use SvelteComponent instead. See PR for more information: 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> {}