TypeScript-Unterstützung in Svelte
Im letzten Artikel haben wir Svelte Stores kennengelernt und sogar unseren eigenen benutzerdefinierten Store implementiert, um die Informationen der App im Web-Speicher zu speichern. Außerdem haben wir uns angesehen, wie man die transition
-Direktive verwendet, um Animationen an DOM-Elementen in Svelte zu implementieren.
Jetzt lernen wir, wie man TypeScript in Svelte-Anwendungen verwendet. Zuerst erfahren wir, was TypeScript ist und welche Vorteile es uns bieten kann. Dann sehen wir uns an, wie wir unser Projekt konfigurieren, um mit TypeScript-Dateien zu arbeiten. Schließlich gehen wir unsere App durch und sehen, welche Änderungen wir vornehmen müssen, um die Funktionen von TypeScript voll auszunutzen.
Voraussetzungen: |
Es wird mindestens empfohlen, dass Sie mit den grundlegenden HTML, CSS und JavaScript Sprachen vertraut sind und Kenntnisse im Umgang mit dem Terminal/Befehlszeile haben. Sie benötigen ein Terminal mit installiertem Node und npm, um Ihre Anwendung zu kompilieren und zu erstellen. |
---|---|
Ziel: | Lernen, wie man TypeScript beim Entwickeln von Svelte-Anwendungen konfiguriert und verwendet. |
Beachten Sie, dass unsere Anwendung vollständig funktionsfähig ist und das Portieren auf TypeScript völlig optional ist. Darüber gibt es verschiedene Meinungen, und in diesem Kapitel werden wir kurz über die Vor- und Nachteile von TypeScript sprechen. Selbst wenn Sie nicht planen, es zu verwenden, wird dieser Artikel nützlich sein, um zu verstehen, was es zu bieten hat und Ihnen helfen, Ihre eigene Entscheidung zu treffen. Wenn Sie sich überhaupt nicht für TypeScript interessieren, können Sie zum nächsten Kapitel springen, in dem wir uns verschiedene Optionen zum Bereitstellen unserer Svelte-Anwendungen, weitere Ressourcen und mehr ansehen.
Gemeinsam mit uns Coden
Git
Klonen Sie das GitHub-Repo (falls Sie dies noch nicht getan haben) mit:
git clone https://github.com/opensas/mdn-svelte-tutorial.git
Um zum aktuellen Status der App zu gelangen, führen Sie aus:
cd mdn-svelte-tutorial/07-typescript-support
Oder laden Sie den Inhalt des Ordners direkt herunter:
npx degit opensas/mdn-svelte-tutorial/07-typescript-support
Vergessen Sie nicht, npm install && npm run dev
auszuführen, um Ihre App im Entwicklungsmodus zu starten.
REPL
Leider ist die TypeScript-Unterstützung noch nicht im REPL verfügbar.
TypeScript: optionale statische Typisierung für JavaScript
TypeScript ist eine erweiterte Version von JavaScript, die Funktionen wie optionale statische Typisierung, Klassen, Schnittstellen und Generics bietet. Das Ziel von TypeScript ist es, Fehler frühzeitig durch sein Typsystem zu erkennen und die JavaScript-Entwicklung effizienter zu gestalten. Einer der großen Vorteile ist die Ermöglichung von umfangreicheren Entwicklungsumgebungen, die Fehler bereits beim Tippen des Codes erkennen.
Das Beste daran ist, dass JavaScript-Code gültiger TypeScript-Code ist; TypeScript ist eine Obermenge von JavaScript. Sie können die meisten Ihrer .js
-Dateien in .ts
-Dateien umbenennen, und sie werden einfach funktionieren.
Unser TypeScript-Code wird überall dort ausgeführt werden können, wo JavaScript ausgeführt werden kann. Wie ist das möglich? TypeScript "transpiliert" unseren Code zu standardmäßigem JavaScript. Das bedeutet, dass es TypeScript-Code analysiert und den entsprechenden Standard-JavaScript-Code erzeugt, den Browser ausführen können.
Hinweis: Wenn Sie neugierig sind, wie TypeScript unseren Code nach JavaScript transpiliert, können Sie sich den TypeScript Playground ansehen.
Erstklassige TypeScript-Unterstützung war die am meisten geforderte Funktion von Svelte seit geraumer Zeit. Dank der harten Arbeit des Svelte-Teams, zusammen mit vielen Mitwirkenden, haben sie eine offizielle Lösung bereit, die getestet werden kann. In diesem Abschnitt zeigen wir Ihnen, wie Sie ein Svelte-Projekt mit TypeScript-Unterstützung einrichten, um es auszuprobieren.
Warum TypeScript?
Die Hauptvorteile von TypeScript sind:
- Frühzeitige Fehlererkennung: Der Compiler prüft die Typen zur Kompilierungszeit und liefert Fehlermeldungen.
- Lesbarkeit: Die statische Typisierung verleiht dem Code mehr Struktur, macht ihn selbstdokumentierend und leichter lesbar.
- Umfangreiche IDE-Unterstützung: Typinformationen ermöglichen es Code-Editoren und IDEs, Funktionen wie Code-Navigation, Autovervollständigung und intelligentere Hinweise anzubieten.
- Sichere Refaktorisierung: Typen ermöglichen es IDEs, mehr über Ihren Code zu wissen und Ihnen beim Refaktorieren großer Teile Ihres Code-Basis zu helfen.
- Typinferenz: Ermöglicht die Nutzung vieler TypeScript-Funktionen, auch ohne Variablentypen zu deklarieren.
- Verfügbarkeit von neuen und zukünftigen JavaScript-Funktionen: TypeScript transpiliert viele aktuelle JavaScript-Funktionen in einfaches, altes JavaScript, sodass Sie sie auch dann verwenden können, wenn sie in Nutzeragenten noch nicht nativ unterstützt werden.
TypeScript hat auch einige Nachteile:
- Keine echte statische Typisierung: Typen werden nur zur Kompilierungszeit geprüft und aus dem generierten Code entfernt.
- Steile Lernkurve: Obwohl TypeScript eine Obermenge von JavaScript ist und keine völlig neue Sprache, gibt es eine beträchtliche Lernkurve, insbesondere wenn Sie keine Erfahrungen mit statischen Sprachen wie Java oder C# haben.
- Mehr Code: Sie müssen mehr Code schreiben und pflegen.
- Kein Ersatz für automatische Tests: Auch wenn Typen helfen können, viele Fehler zu erkennen, ist TypeScript kein wahrer Ersatz für eine umfassende Suite automatisierter Tests.
- Boilerplate-Code: Die Arbeit mit Typen, Klassen, Schnittstellen und Generics kann zu übermäßig engineered Code-Basen führen.
Es scheint einen breiten Konsens zu geben, dass TypeScript besonders gut für groß angelegte Projekte geeignet ist, an denen viele Entwickler am selben Code arbeiten. Und es wird tatsächlich von mehreren großangelegten Projekten verwendet, wie Angular 2, Vue 3, Ionic, Visual Studio Code, Jest und selbst dem Svelte-Compiler. Dennoch ziehen es einige Entwickler vor, es auch in kleinen Projekten wie dem, das wir entwickeln, zu verwenden.
Letztendlich liegt die Entscheidung bei Ihnen. In den folgenden Abschnitten hoffen wir, Ihnen mehr Beweise liefern zu können, um Ihre Meinung dazu zu bilden.
Erstellen eines Svelte TypeScript-Projekts von Grund auf
Sie können ein neues Svelte TypeScript-Projekt mit der standardmäßigen Vorlage starten. Alles, was Sie tun müssen, ist, die folgenden Befehle im Terminal auszuführen (führen Sie sie an einem Ort aus, an dem Sie Ihre Svelte-Testprojekte speichern — es wird ein neues Verzeichnis erstellt):
npx degit sveltejs/template svelte-typescript-app
cd svelte-typescript-app
node scripts/setupTypeScript.js
Dies erstellt ein Starter-Projekt mit TypeScript-Unterstützung, das Sie dann nach Belieben anpassen können.
Dann müssen Sie npm anweisen, Abhängigkeiten herunterzuladen und das Projekt im Entwicklungsmodus zu starten, wie wir es normalerweise tun:
npm install
npm run dev
Hinzufügen von TypeScript-Unterstützung zu einem bestehenden Svelte-Projekt
Um ein bestehendes Svelte-Projekt um TypeScript-Unterstützung zu erweitern, können Sie diese Anleitung befolgen. Alternativ können Sie die Datei setupTypeScript.js
in einen scripts
-Ordner innerhalb Ihres Projekt-Root-Verzeichnisses herunterladen und dann node scripts/setupTypeScript.js
ausführen.
Sie können sogar degit
verwenden, um das Skript herunterzuladen. Genau das werden wir tun, um mit dem Portieren unserer Anwendung auf TypeScript zu beginnen.
Hinweis:
Denken Sie daran, dass Sie npx degit opensas/mdn-svelte-tutorial/07-typescript-support svelte-todo-typescript
ausführen können, um die vollständige To-Do-Liste-Anwendung in JavaScript zu erhalten, bevor Sie beginnen, diese auf TypeScript zu portieren.
Wechseln Sie ins Root-Verzeichnis des Projekts und geben Sie diese Befehle ein:
npx degit sveltejs/template/scripts scripts # download script file to a scripts folder
node scripts/setupTypeScript.js # run it
# Converted to TypeScript.
Sie müssen Ihren Abhängigkeitsmanager neu ausführen, um loszulegen.
npm install # download new dependencies
npm run dev # start the app in development mode
Diese Anweisungen gelten für jedes Svelte-Projekt, das Sie zu TypeScript konvertieren möchten. Beachten Sie nur, dass die Svelte-Community die Svelte TypeScript-Unterstützung ständig verbessert, sodass Sie npm update
regelmäßig ausführen sollten, um die neuesten Änderungen zu nutzen.
Hinweis: Wenn Sie auf Probleme stoßen, TypeScript in einer Svelte-Anwendung zu verwenden, schauen Sie sich diese Fehlerbehebung/FAQ-Sektion zur TypeScript-Unterstützung an.
Wie bereits erwähnt, ist TypeScript eine Obermenge von JavaScript, sodass Ihre Anwendung ohne Änderungen ausgeführt wird. Derzeit führen Sie eine reguläre JavaScript-Anwendung mit aktivierter TypeScript-Unterstützung aus, ohne die Vorteile der von TypeScript bereitgestellten Funktionen zu nutzen. Sie können jetzt damit beginnen, nach und nach Typen hinzuzufügen.
Nachdem Sie TypeScript konfiguriert haben, können Sie es in einer Svelte-Komponente verwenden, indem Sie einfach <script lang='ts'>
am Anfang des Script-Bereichs hinzufügen. Um es in regulären JavaScript-Dateien zu verwenden, ändern Sie einfach die Dateierweiterung von .js
in .ts
. Sie müssen auch alle entsprechenden Import-Anweisungen aktualisieren, um die .ts
Dateierweiterung aus allen import
-Anweisungen zu entfernen.
Hinweis:
TypeScript wird einen Fehler auslösen, wenn Sie die .ts
Dateierweiterung in einer import
-Anweisung verwenden, daher müssen Sie, wenn Sie eine Datei ./foo.ts
haben, diese als "./foo" importieren.
Siehe die Modulauflösung für Bundler, TypeScript-Laufzeiten und Node.js-Loader Sektion des TypeScript-Handbuchs für weitere Informationen.
Hinweis:
Die Verwendung von TypeScript in Markup-Bereichen von Komponenten wird in Svelte 4, auf dem dieser Leitfaden basiert, nicht unterstützt.
Während Sie JavaScript aus dem Markup verwenden können, müssen Sie TypeScript im <script lang='ts'>
-Bereich verwenden.
TypeScript in Komponenten-Markup ist ab Svelte 5 erlaubt.
Verbesserte Entwicklererfahrung mit TypeScript
TypeScript stellt Code-Editoren und IDEs viele Informationen zur Verfügung, um eine benutzerfreundlichere Entwicklererfahrung zu ermöglichen.
Wir werden Visual Studio Code verwenden, um einen kurzen Test durchzuführen und zu sehen, wie wir Autovervollständigungshinweise und Typüberprüfung erhalten können, während wir Komponenten schreiben.
Hinweis: Wenn Sie VS Code nicht verwenden möchten, bieten wir etwas später auch Anweisungen zur Verwendung der TypeScript-Fehlerprüfung über das Terminal an.
Es gibt laufende Arbeiten, um TypeScript in Svelte-Projekten in mehreren Code-Editoren zu unterstützen; die vollständigste Unterstützung ist derzeit in der Svelte für VS Code-Erweiterung verfügbar, die vom Svelte-Team entwickelt und gepflegt wird. Diese Erweiterung bietet Typüberprüfung, Inspektion, Refaktorisierung, Intellisense, Hover-Informationen, Autovervollständigung und andere Funktionen. Diese Art von Entwicklerunterstützung ist ein weiterer guter Grund, TypeScript in Ihren Projekten zu verwenden.
Hinweis: Stellen Sie sicher, dass Sie Svelte für VS Code und NICHT das alte "Svelte" von James Birtles verwenden, welches eingestellt wurde. Falls Sie es installiert haben, sollten Sie es deinstallieren und die offizielle Svelte-Erweiterung stattdessen installieren.
Angenommen, Sie befinden sich innerhalb der VS Code-Anwendung, geben Sie am Projekthauptverzeichnis code .
ein (der nachfolgende Punkt weist VS Code an, das aktuelle Verzeichnis zu öffnen), um den Code-Editor zu öffnen. VS Code weist Sie darauf hin, dass empfohlene Erweiterungen zur Installation verfügbar sind.
Durch Klicken auf Alle installieren wird Svelte für VS Code installiert.
Wir sehen auch, dass die Datei setupTypeScript.js
einige Änderungen an unserem Projekt vorgenommen hat. Die Datei main.js
wurde in main.ts
umbenannt, was bedeutet, dass VS Code Hover-Informationen zu unseren Svelte-Komponenten bereitstellen kann:
Wir erhalten auch die Typüberprüfung kostenlos. Wenn wir eine unbekannte Eigenschaft im options-Parameter des App
-Konstruktors übergeben (z. B. ein Tippfehler wie traget
anstelle von target
), wird TypeScript sich beschweren:
Im App.svelte
Komponenten hat das Script setupTypeScript.js
das lang="ts"
Attribut zum <script>
Tag hinzugefügt. Darüber hinaus, dank der Typinferenz, müssen wir in vielen Fällen keine Typen mehr angeben, um Zugang zu Codeassistenz zu erhalten. Wenn Sie beispielsweise beginnen, ein ms
-Eigenschaft zum Aufruf der Alert
-Komponente hinzuzufügen, sieht TypeScript anhand des Standardwerts, dass die ms
-Eigenschaft eine Zahl sein sollte:
Und wenn Sie etwas anderes als eine Zahl übergeben, wird es sich darüber beschweren:
Das Anwendungs-Template hat ein check
-Skript konfiguriert, das svelte-check
gegen Ihren Code ausführt. Dieses Paket ermöglicht es Ihnen, Fehler und Warnungen, die normalerweise von einem Code-Editor angezeigt werden, von der Befehlszeile aus zu erkennen. Dies macht es ziemlich nützlich, es in einer kontinuierlichen Integrationspipeline (CI) auszuführen. Führen Sie einfach npm run check
aus, um nicht verwendetes CSS zu überprüfen und A11y-Hinweise sowie TypeScript-Kompilierungsfehler zurückzugeben.
In diesem Fall, wenn Sie npm run check
ausführen (entweder in der VS Code Konsole oder dem Terminal), erhalten Sie den folgenden Fehler:
Noch besser, wenn Sie es aus dem integrierten terminal von VS Code ausführen (Sie können es mit der Tastenkombination Strg + ` öffnen), führt ein Befehl/Strg-Klick auf den Dateinamen direkt zur Zeile mit dem Fehler.
Sie können das check
-Skript auch im Überwachungsmodus mit npm run check -- --watch
ausführen. In diesem Fall wird das Skript jedes Mal ausgeführt, wenn Sie eine Datei ändern. Wenn Sie dies in Ihrem regulären Terminal ausführen, halten Sie es im Hintergrund in einem separaten Terminalfenster offen, sodass es weiterhin Fehler melden kann, aber nicht Ihre anderen Terminalnutzungen stört.
Erstellen eines benutzerdefinierten Typs
TypeScript unterstützt strukturelle Typisierung. Strukturelle Typisierung ist eine Methode, Typen ausschließlich basierend auf ihren Mitgliedern in Beziehung zu setzen, selbst wenn Sie den Typ nicht explizit definieren.
Wir definieren einen TodoType
Typ, um zu sehen, wie TypeScript durchsetzt, dass alles, was an eine Komponente übergeben wird, die einen TodoType
erwartet, strukturell mit diesem kompatibel ist.
-
Erstellen Sie am Anfang einen
types
-Ordner imsrc
-Verzeichnis. -
Fügen Sie diesem Ordner eine
todo.type.ts
-Datei hinzu. -
Der Inhalt von
todo.type.ts
sollte wie folgt sein:tsexport type TodoType = { id: number; name: string; completed: boolean; };
Hinweis: Das Svelte Template verwendet svelte-preprocess 4.0.0, um TypeScript zu unterstützen. Ab dieser Version müssen Sie die
export
/import
-Syntax verwenden, um Typen und Schnittstellen zu importieren. Überprüfen Sie diesen Abschnitt des Fehlerbehebungsleitfadens für weitere Informationen. -
Nun verwenden wir
TodoType
von unsererTodo.svelte
-Komponente. Fügen Sie zuerst dem<script>
-Taglang="ts"
hinzu. -
Importieren Sie den Typ und verwenden Sie ihn, um die
todo
-Eigenschaft zu deklarieren. Ersetzen Sie die Zeileexport let todo
durch folgende Zeile:tsimport type { TodoType } from "../types/todo.type"; export let todo: TodoType;
Beachten Sie, dass die
.ts
Dateierweiterung in derimport
-Anweisung nicht erlaubt ist und weggelassen wurde. -
Jetzt instanziieren wir eine
Todo
-Komponente mit einem Literalen Objekt als Parameter vor dem Aufruf derMoreActions
-Komponente, so:svelte<hr /> <Todo todo={ { name: 'a new task with no id!', completed: false } } /> <!-- MoreActions --> <MoreActions {todos}
-
Fügen Sie dem
<script>
-Tag derTodos.svelte
-Komponentelang='ts'
hinzu, damit Codeüberprüfung verwendet wird, die wir spezifiziert haben.Wir erhalten den folgenden Fehler:
Nun sollten Sie eine Vorstellung davon bekommen, welche Art von Unterstützung wir von TypeScript erhalten können, wenn wir Svelte-Projekte erstellen.
Jetzt machen wir diese Änderungen rückgängig, um mit dem Portieren unserer Anwendung auf TypeScript zu beginnen, damit wir nicht durch alle Prüfwarnungen gestört werden.
- Entfernen Sie das fehlerhafte To-Do und das
lang='ts'
-Attribut aus der DateiTodos.svelte
. - Entfernen Sie auch den Import von
TodoType
und daslang='ts'
ausTodo.svelte
.
Wir werden sie später ordnungsgemäß bearbeiten.
Portieren unserer To-Do-Liste App zu TypeScript
Jetzt sind wir bereit, damit zu beginnen, unsere To-Do-Liste Applikation zu portieren, um all die Funktionen zu nutzen, die TypeScript uns bietet.
Beginnen wir damit, das Check-Skript im Überwachungsmodus im Projektstammverzeichnis auszuführen:
npm run check -- --watch
Dies sollte etwas wie folgendes ausgeben:
svelte-check "--watch"
Loading svelte-check in workspace: ./svelte-todo-typescript
Getting Svelte diagnostics...
====================================
svelte-check found no errors and no warnings
Beachten Sie, dass wenn Sie einen unterstützenden Code-Editor wie VS Code verwenden, es einfach ist, damit zu beginnen, eine Svelte-Komponente zu portieren, indem Sie einfach das <script lang='ts'>
oben in Ihrer Komponente hinzufügen und nach den dreigepunkteten Hinweisen suchen:
Alert.svelte
Beginnen wir mit unserer Alert.svelte
Komponente.
-
Fügen Sie
lang="ts"
in die<script>
-Tag IhrerAlert.svelte
Komponente ein. Sie werden einige Warnungen in der Ausgabe descheck
-Skripts sehen:bashnpm run check -- --watch
> svelte-check "--watch" ./svelte-todo-typescript Getting Svelte diagnostics... ==================================== ./svelte-todo-typescript/src/components/Alert.svelte:8:7 Warn: Variable 'visible' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) let visible ./svelte-todo-typescript/src/components/Alert.svelte:9:7 Warn: Variable 'timeout' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) let timeout ./svelte-todo-typescript/src/components/Alert.svelte:11:28 Warn: Parameter 'message' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) Change = (message, ms) => { ./svelte-todo-typescript/src/components/Alert.svelte:11:37 Warn: Parameter 'ms' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) (message, ms) => {
-
Sie können diese beheben, indem Sie die entsprechenden Typen angeben, so:
tsexport let ms = 3000 let visible: boolean let timeout: number const onMessageChange = (message: string, ms: number) => { clearTimeout(timeout) if (!message) { // hide Alert if message is empty
Hinweis: Es gibt keine Notwendigkeit, den
ms
-Typ mitexport let ms:number = 3000
anzugeben, da TypeScript dies bereits anhand des Standardwerts ableitet.
MoreActions.svelte
Jetzt machen wir das gleiche für die MoreActions.svelte
Komponente.
-
Fügen Sie das
lang='ts'
-Attribut wie zuvor hinzu. TypeScript wird uns bezüglich dertodos
-Eigenschaft und dert
-Variable im Aufruf vontodos.filter((t) =>...)
warnen.Warn: Variable 'todos' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) export let todos Warn: Parameter 't' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) $: completedTodos = todos.filter((t) => t.completed).length
-
Wir werden den bereits definierten
TodoType
verwenden, um TypeScript mitzuteilen, dasstodos
einTodoType
-Array ist. Ersetzen Sie dieexport let todos
-Zeile durch folgende:tsimport type { TodoType } from "../types/todo.type"; export let todos: TodoType[];
Beachten Sie, dass TypeScript jetzt erkennen kann, dass die t
-Variable in todos.filter((t) => t.completed)
vom Typ TodoType
ist. Wenn wir jedoch denken, dass dies unseren Code leichter lesbar macht, könnten wir es so spezifizieren:
$: completedTodos = todos.filter((t: TodoType) => t.completed).length;
Meistens kann TypeScript den reaktiven Variablentyp richtig ableiten, aber manchmal können Sie einen "hat implizit den Typ 'any' Fehler" erhalten, wenn Sie mit reaktiven Zuweisungen arbeiten. In diesen Fällen können Sie die typisierte Variable in einer separaten Anweisung deklarieren, wie so:
let completedTodos: number;
$: completedTodos = todos.filter((t: TodoType) => t.completed).length;
Sie können den Typ nicht in der reaktiven Zuweisung selbst angeben. Die Anweisung $: completedTodos: number = todos.filter[...]
ist ungültig. Für weitere Informationen lesen Sie Wie typisiere ich reaktive Zuweisungen? / Ich erhalte einen "implizit hat Typ 'any' Fehler".
FilterButton.svelte
Jetzt kümmern wir uns um die FilterButton
Komponente.
-
Fügen Sie das
lang='ts'
-Attribut zum<script>
-Tag hinzu, wie gewohnt. Es folgen keine Warnungen — TypeScript leitet den Typ der Filtervariable von dem Standardwert ab. Aber wir wissen, dass es nur drei gültige Werte für den Filter gibt: all, active und completed. Daher können wir TypeScript darüber informieren, indem wir eine Aufzählung Filter erstellen. -
Erstellen Sie eine
filter.enum.ts
-Datei imtypes
-Ordner. -
Geben Sie ihr folgende Inhalte:
tsexport enum Filter { ALL = "all", ACTIVE = "active", COMPLETED = "completed", }
-
Nun verwenden wir dies von der
FilterButton
-Komponente aus. Ersetzen Sie den Inhalt der DateiFilterButton.svelte
durch Folgendes:svelte<!-- components/FilterButton.svelte --> <script lang="ts"> import { Filter } from "../types/filter.enum"; export let filter: Filter = Filter.ALL; </script> <div class="filters btn-group stack-exception"> <button class="btn toggle-btn" class:btn__primary={filter === Filter.ALL} aria-pressed={filter === Filter.ALL} on:click={()=> filter = Filter.ALL} > <span class="visually-hidden">Show</span> <span>All</span> <span class="visually-hidden">tasks</span> </button> <button class="btn toggle-btn" class:btn__primary={filter === Filter.ACTIVE} aria-pressed={filter === Filter.ACTIVE} on:click={()=> filter = Filter.ACTIVE} > <span class="visually-hidden">Show</span> <span>Active</span> <span class="visually-hidden">tasks</span> </button> <button class="btn toggle-btn" class:btn__primary={filter === Filter.COMPLETED} aria-pressed={filter === Filter.COMPLETED} on:click={()=> filter = Filter.COMPLETED} > <span class="visually-hidden">Show</span> <span>Completed</span> <span class="visually-hidden">tasks</span> </button> </div>
Hier importieren wir nur die Filter
-Aufzählung und verwenden sie anstelle der vorher verwendeten Zeichenfolgenwerte.
Todos.svelte
Wir werden auch die Filter
-Aufzählung in der Todos.svelte
-Komponente verwenden.
-
Fügen Sie zuerst das
lang='ts'
-Attribut hinzu, wie zuvor. -
Importieren Sie die
Filter
-Aufzählung. Fügen Sie folgendeimport
-Anweisung unter Ihren bestehenden hinzu:jsimport { Filter } from "../types/filter.enum";
-
Jetzt werden wir sie verwenden, wann immer wir den aktuellen Filter referenzieren. Ersetzen Sie Ihre beiden Filter-bezogenen Blöcke durch Folgendes:
tslet filter: Filter = Filter.ALL; const filterTodos = (filter: Filter, todos) => filter === Filter.ACTIVE ? todos.filter((t) => !t.completed) : filter === Filter.COMPLETED ? todos.filter((t) => t.completed) : todos; $: { if (filter === Filter.ALL) { $alert = "Browsing all todos"; } else if (filter === Filter.ACTIVE) { $alert = "Browsing active todos"; } else if (filter === Filter.COMPLETED) { $alert = "Browsing completed todos"; } }
-
Der
check
gibt uns immer noch einige Warnungen vonTodos.svelte
. Lass uns sie beheben.Beginnen Sie den
TodoType
zu importieren und sagen Sie TypeScript, dass unseretodos
-Variable ein Array vonTodoType
ist. Ersetzen Sieexport let todos = []
durch die folgenden zwei Zeilen:tsimport type { TodoType } from "../types/todo.type"; export let todos: TodoType[] = [];
-
Als nächstes werden wir alle fehlenden Typen angeben. Die Variable
todosStatus
, die wir verwendet haben, um programmatisch auf die Methoden zuzugreifen, die von derTodosStatus
-Komponente bereitgestellt werden, hat den TypTodosStatus
. Und jedertodo
wird vom TypTodoType
sein.Aktualisieren Sie Ihren
<script>
Abschnitt, um wie folgt auszusehen:tsimport FilterButton from "./FilterButton.svelte"; import Todo from "./Todo.svelte"; import MoreActions from "./MoreActions.svelte"; import NewTodo from "./NewTodo.svelte"; import TodosStatus from "./TodosStatus.svelte"; import { alert } from "../stores"; import { Filter } from "../types/filter.enum"; import type { TodoType } from "../types/todo.type"; export let todos: TodoType[] = []; let todosStatus: TodosStatus; // reference to TodosStatus instance $: newTodoId = todos.length > 0 ? Math.max(...todos.map((t) => t.id)) + 1 : 1; function addTodo(name: string) { todos = [...todos, { id: newTodoId, name, completed: false }]; $alert = `Todo '${name}' has been added`; } function removeTodo(todo: TodoType) { todos = todos.filter((t) => t.id !== todo.id); todosStatus.focus(); // give focus to status heading $alert = `Todo '${todo.name}' has been deleted`; } function updateTodo(todo: TodoType) { const i = todos.findIndex((t) => t.id === todo.id); if (todos[i].name !== todo.name) $alert = `todo '${todos[i].name}' has been renamed to '${todo.name}'`; if (todos[i].completed !== todo.completed) $alert = `todo '${todos[i].name}' marked as ${ todo.completed ? "completed" : "active" }`; todos[i] = { ...todos[i], ...todo }; } let filter: Filter = Filter.ALL; const filterTodos = (filter: Filter, todos: TodoType[]) => filter === Filter.ACTIVE ? todos.filter((t) => !t.completed) : filter === Filter.COMPLETED ? todos.filter((t) => t.completed) : todos; $: { if (filter === Filter.ALL) { $alert = "Browsing all todos"; } else if (filter === Filter.ACTIVE) { $alert = "Browsing active todos"; } else if (filter === Filter.COMPLETED) { $alert = "Browsing completed todos"; } } const checkAllTodos = (completed: boolean) => { todos = todos.map((t) => ({ ...t, completed })); $alert = `${completed ? "Checked" : "Unchecked"} ${todos.length} todos`; }; const removeCompletedTodos = () => { $alert = `Removed ${todos.filter((t) => t.completed).length} todos`; todos = todos.filter((t) => !t.completed); };
TodosStatus.svelte
Wir haben die folgenden Fehler im Zusammenhang mit der Übergabe von todos
an die TodosStatus.svelte
(und Todo.svelte
) Komponenten:
./src/components/Todos.svelte:70:39 Error: Type 'TodoType[]' is not assignable to type 'undefined'. (ts) <TodosStatus bind:this={todosStatus} {todos} /> ./src/components/Todos.svelte:76:12 Error: Type 'TodoType' is not assignable to type 'undefined'. (ts) <Todo {todo}
Das liegt daran, dass die todos
-Eigenschaft in der TodosStatus
-Komponente keinen Standardwert hat, TypeScript sie daher als Typ undefined
angenommen hat, der nicht mit einem Array von TodoType
kompatibel ist. Dasselbe Problem tritt bei unserer Todo-Komponente auf.
Lass uns das beheben.
-
Öffnen Sie die Datei
TodosStatus.svelte
und fügen Sie daslang='ts'
-Attribut hinzu. -
Importieren Sie dann den
TodoType
und deklarieren Sie dietodos
-Eigenschaft als ein Array vonTodoType
. Ersetzen Sie die erste Zeile des<script>
Abschnitts mit folgendem:tsimport type { TodoType } from "../types/todo.type"; export let todos: TodoType[];
-
Wir spezifizieren außerdem das
headingEl
, das wir zum Binden an das Überschriftentag verwendet haben, alsHTMLElement
. Aktualisieren Sie dielet headingEl
-Zeile mit folgendem:tslet headingEl: HTMLElement;
-
Schließlich werden Sie den folgenden Fehler gemeldet sehen, der sich auf die Stelle bezieht, an der wir das
tabindex
-Attribut setzen. Das liegt daran, dass TypeScript das<h2>
-Element typüberprüft und erwartet, dasstabindex
vom Typnumber
ist.Um dies zu beheben, ersetzen Sie
tabindex="-1"
durchtabindex={-1}
, so:svelte<h2 id="list-heading" bind:this={headingEl} tabindex={-1}> {completedTodos} out of {totalTodos} items completed </h2>
So kann TypeScript verhindern, dass wir es fälschlicherweise auf eine Zeichenfolgenvariable setzen.
NewTodo.svelte
Als Nächstes kümmern wir uns um NewTodo.svelte
.
-
Fügen Sie wie gewohnt das
lang='ts'
-Attribut hinzu. -
Die Warnung weist darauf hin, dass wir einen Typ für die
nameEl
-Variable angeben müssen. Legen Sie ihren Typ alsHTMLElement
fest, so:tslet nameEl: HTMLElement; // reference to the name input DOM node
-
Zuletzt für diese Datei müssen wir den richtigen Typ für unsere
autofocus
-Variable angeben. Aktualisieren Sie deren Definition wie so:tsexport let autofocus: boolean = false;
Todo.svelte
Nun sind die einzigen Warnungen, die npm run check
ausgibt, durch das Aufrufen der Todo.svelte
-Komponente ausgelöst. Lassen Sie uns diese beheben.
-
Öffnen Sie die
Todo.svelte
-Datei und fügen Sie daslang='ts'
-Attribut hinzu. -
Lassen Sie uns den Typ
TodoType
importieren und den Typ dertodo
-Eigenschaft festlegen. Ersetzen Sie die Zeileexport let todo
durch folgende Zeile:tsimport type { TodoType } from "../types/todo.type"; export let todo: TodoType;
-
Die erste Warnung, die wir erhalten, ist, dass uns TypeScript bittet, den Typ der
update()
-FunktionupdatedTodo
-Variable zu definieren. Dies kann etwas knifflig sein, daupdatedTodo
nur die aktualisierten Attribute destodo
enthält. Das bedeutet, dass es kein vollständigestodo
ist — es hat nur eine Teilmenge der Eigenschaften einestodo
.Für diese Arten von Fällen stellt TypeScript mehrere Utility-Typen zur Verfügung, die es einfacher machen, diese gängigen Transformationen anzuwenden. Was wir jetzt brauchen, ist der
Partial<T>
Utility-Typ, der es ermöglicht, alle Teilmengen eines angegebenen Typs darzustellen. Der Partial-Utility gibt einen neuen Typ auf Basis des TypsT
zurück, bei dem jede Eigenschaft vonT
optional ist.Wir werden ihn in der
update()
-Funktion verwenden — aktualisieren Sie dafür so:tsfunction update(updatedTodo: Partial<TodoType>) { todo = { ...todo, ...updatedTodo }; // applies modifications to todo dispatch("update", todo); // emit update event }
Damit teilen wir TypeScript mit, dass die
updatedTodo
Variable eine Teilmenge derTodoType
-Eigenschaften enthalten wird. -
Nun sagt uns svelte-check, dass wir den Typ unserer Aktionsfunktionparameter definieren müssen:
bash./07-next-steps/src/components/Todo.svelte:45:24 Warn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) const focusOnInit = (node) => node && typeof node.focus === 'function' && node.focus() ./07-next-steps/src/components/Todo.svelte:47:28 Warn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) const focusEditButton = (node) => editButtonPressed && node.focus()
Wir müssen nur die
node
Variable alsHTMLElement
definieren. Ersetzen Sie in den beiden oben angegebenen Zeilen die erste Instanz vonnode
durchnode: HTMLElement
.
actions.js
Als Nächstes kümmern wir uns um die Datei actions.js
.
-
Benennen Sie sie in
actions.ts
um und geben Sie den Typ des node Parameters an. Es sollte folgendermaßen aussehen:ts// actions.ts export function selectOnFocus(node: HTMLInputElement) { if (node && typeof node.select === "function") { // make sure node is defined and has a select() method const onFocus = () => node.select(); // event handler node.addEventListener("focus", onFocus); // when node gets focus call onFocus() return { destroy: () => node.removeEventListener("focus", onFocus), // this will be executed when the node is removed from the DOM }; } }
-
Aktualisieren Sie
Todo.svelte
undNewTodo.svelte
, wo wir die actions-Datei importieren. Denken Sie daran, dass Importe in TypeScript die Dateierweiterung nicht enthalten. In jedem Fall sollte es folgendermaßen aussehen:jsimport { selectOnFocus } from "../actions";
Migrieren der Stores zu TypeScript
Nun müssen wir die Dateien stores.js
und localStore.js
zu TypeScript konvertieren.
Tipp: Das Script npm run check
, das das svelte-check
Tool verwendet, prüft nur die .svelte
-Dateien unserer Anwendung. Wenn Sie auch die .ts
-Dateien überprüfen möchten, können Sie npm run check && npx tsc --noEmit
ausführen, was dem TypeScript-Compiler sagt, nach Fehlern zu suchen, ohne die .js
-Ausgabedateien zu generieren. Sie könnten sogar ein Skript zu Ihrer package.json
-Datei hinzufügen, das diesen Befehl ausführt.
Wir beginnen mit stores.js
.
-
Benennen Sie die Datei in
stores.ts
um. -
Setzen Sie den Typ unseres
initialTodos
-Arrays zuTodoType[]
. Der Inhalt wird folgendermaßen aussehen:ts// stores.ts import { writable } from "svelte/store"; import { localStore } from "./localStore.js"; import type { TodoType } from "./types/todo.type"; export const alert = writable("Welcome to the To-Do list app!"); const initialTodos: TodoType[] = [ { id: 1, name: "Visit MDN web docs", completed: true }, { id: 2, name: "Complete the Svelte Tutorial", completed: false }, ]; export const todos = localStore("mdn-svelte-todo", initialTodos);
-
Denken Sie daran, die
import
-Anweisungen inApp.svelte
,Alert.svelte
undTodos.svelte
zu aktualisieren. Entfernen Sie einfach die.js
-Erweiterung, so:jsimport { todos } from "../stores";
Nun zu localStore.js
.
Aktualisieren Sie die import
-Anweisung in stores.ts
so:
import { localStore } from "./localStore";
-
Beginnen Sie damit, die Datei in
localStore.ts
umzubenennen. -
TypeScript sagt uns, dass wir den Typ der
key
,initial
undvalue
-Variablen angeben sollen. Der erste ist einfach: Der Schlüssel unseres lokalen Webspeichers sollte eine Zeichenkette sein.Aber
initial
undvalue
sollten jedes beliebige Objekt sein, das zu einem gültigen JSON-String mit derJSON.stringify
Methode konvertiert werden kann, was jedes JavaScript-Objekt mit ein paar Einschränkungen bedeutet: Zum Beispiel sindundefined
, Funktionen und Symbole keine gültigen JSON-Werte.Daher erstellen wir den Typ
JsonValue
, um diese Bedingungen zu spezifizieren.Erstellen Sie die Datei
json.type.ts
imtypes
-Ordner. -
Geben Sie ihr folgenden Inhalt:
tsexport type JsonValue = | string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
Der
|
-Operator erlaubt uns, Variablen zu deklarieren, die Werte von zwei oder mehr Typen speichern könnten. EinJsonValue
könnte eine Zeichenkette, eine Zahl, ein Boolescher Wert und so weiter sein. In diesem Fall nutzen wir auch rekursive Typen, um zu spezifizieren, dass einJsonValue
ein Array vonJsonValue
haben kann und auch ein Objekt mit Eigenschaften vom TypJsonValue
. -
Wir importieren unseren
JsonValue
-Typ und verwenden ihn entsprechend. Aktualisieren Sie IhrelocalStore.ts
-Datei so:ts// localStore.ts import { writable } from "svelte/store"; import type { JsonValue } from "./types/json.type"; export const localStore = (key: string, initial: JsonValue) => { // receives the key of the local storage and an initial value const toString = (value: JsonValue) => JSON.stringify(value, null, 2); // helper function const toObj = JSON.parse; // helper function if (localStorage.getItem(key) === null) { // item not present in local storage localStorage.setItem(key, toString(initial)); // initialize local storage with initial value } const saved = toObj(localStorage.getItem(key)); // convert to object const { subscribe, set, update } = writable(saved); // create the underlying writable store return { subscribe, set: (value: JsonValue) => { localStorage.setItem(key, toString(value)); // save also to local storage as a string return set(value); }, update, }; };
Wenn wir nun versuchen, einen localStore
mit etwas zu erstellen, das nicht mit JSON.stringify()
in JSON konvertiert werden kann, z. B. ein Objekt mit einer Funktion als Eigenschaft, wird VS Code/validate
dies monieren:
Und das Beste daran, es wird sogar mit der $store
-Autoabonnement-Syntax funktionieren. Wenn wir versuchen, einen ungültigen Wert in unserem todos
-Store mit der $store
-Syntax zu speichern, so:
<!-- App.svelte -->
<script lang="ts">
import Todos from "./components/Todos.svelte";
import Alert from "./components/Alert.svelte";
import { todos } from "./stores";
// this is invalid, the content cannot be converted to JSON using JSON.stringify
$todos = { handler: () => {} };
</script>
Das Check-Skript wird den folgenden Fehler melden:
> npm run check
Getting Svelte diagnostics...
====================================
./svelte-todo-typescript/src/App.svelte:8:12
Error: Argument of type '{ handler: () => void; }' is not assignable to parameter of type 'JsonValue'.
Types of property 'handler' are incompatible.
Type '() => void' is not assignable to type 'JsonValue'.
Type '() => void' is not assignable to type '{ [key: string]: JsonValue; }'.
Index signature is missing in type '() => void'. (ts)
$todos = { handler: () => {} }
Dies ist ein weiteres Beispiel dafür, wie die Angabe von Typen unseren Code robuster machen kann und uns helfen kann, mehr Fehler zu erfassen, bevor sie in die Produktion gelangen.
Und das war's. Wir haben unsere gesamte Anwendung konvertiert, um TypeScript zu verwenden.
Unsere Stores mit Generics wasserdicht machen
Unsere Stores wurden bereits nach TypeScript portiert, aber wir können noch besser werden. Wir sollten keinen Wert jedweder Art speichern müssen – wir wissen, dass der Alert Store nur Zeichenfolgenmeldungen enthalten sollte, und der To-Do-Store ein Array von TodoType
usw. Wir können TypeScript dies durchsetzt, indem wir TypeScript Generics verwenden. Lassen Sie uns mehr herausfinden.
Verständnis von TypeScript Generics
Generics ermöglichen das Erstellen von wiederverwendbaren Codekomponenten, die mit verschiedenen Typen anstelle eines einzelnen Typs arbeiten. Sie können auf Schnittstellen, Klassen und Funktionen angewendet werden. Generische Typen werden als Parameter mit einer speziellen Syntax übergeben: Sie werden innerhalb eckiger Klammern angegeben und konventionell mit einem einzelnen Großbuchstaben benannt. Generische Typen ermöglichen es Ihnen, Typen zu erfassen, die vom Benutzer bereitgestellt werden, und stellt sicher, dass sie für die zukünftige Verarbeitung verfügbar sind.
Sehen wir uns ein schnelles Beispiel an, eine einfache Stack
-Klasse, in der wir Elemente push
und pop
können, so:
export class Stack {
private elements = [];
push = (element) => this.elements.push(element);
pop() {
if (this.elements.length === 0) throw new Error("The stack is empty!");
return this.elements.pop();
}
}
In diesem Fall ist elements
ein Array vom Typ any
und dementsprechend empfangen und geben die push()
- und pop()
-Methoden eine Variable vom Typ any
zurück. Daher ist es perfekt gültig, so etwas zu tun:
const anyStack = new Stack();
anyStack.push(1);
anyStack.push("hello");
Aber was, wenn wir einen Stack haben wollten, der nur mit dem Typ string
arbeiten würde? Wir könnten das Folgende tun:
export class StringStack {
private elements: string[] = [];
push = (element: string) => this.elements.push(element);
pop(): string {
if (this.elements.length === 0) throw new Error("The stack is empty!");
return this.elements.pop();
}
}
Das würde funktionieren. Aber wenn wir mit Zahlen arbeiten wollten, müssten wir denselben Code duplizieren und eine NumberStack
-Klasse erstellen. Und wie könnten wir einen Stapel von Typen handhaben, die wir noch nicht kennen und die vom Benutzer definiert werden sollten?
Um all diese Probleme zu lösen, können wir Generika verwenden.
Das ist unsere Stack
-Klasse neu implementiert mit Generics:
export class Stack<T> {
private elements: T[] = [];
push = (element: T): number => this.elements.push(element);
pop(): T {
if (this.elements.length === 0) throw new Error("The stack is empty!");
return this.elements.pop();
}
}
Wir definieren einen generischen Typ T
und verwenden ihn dann, als würden wir normalerweise einen bestimmten Typ verwenden. Jetzt ist elements
ein Array vom Typ T
und push()
und pop()
beide empfangen und geben eine Variable vom Typ T
zurück.
So würden wir unsere generische Stack
verwenden:
const numberStack = new Stack<number>();
numberStack.push(1);
Nun weiß TypeScript, dass unser Stack nur Zahlen akzeptieren kann und gibt einen Fehler aus, wenn wir versuchen, etwas anderes hinzuzufügen:
TypeScript kann auch generische Typen anhand ihrer Verwendung ableiten. Generische Typen unterstützen auch Standardwerte und Einschränkungen.
Generische Typen sind ein mächtiges Feature, das es unserem Code ermöglicht, von den spezifischen Typen abstrahiert zu werden, die verwendet werden, und ihn wiederverwendbarer und generischer zu machen, ohne Sicherheitsüberprüfungen aufzugeben. Um mehr darüber zu erfahren, schauen Sie sich die TypeScript Einführung in Generika an.
Verwendung von Svelte Stores mit Generics
Svelte Stores unterstützen Generics von Haus aus. Und dank der generischen Typenableitung können wir ihre Vorteile nutzen, ohne unseren Code überhaupt zu berühren.
Wenn Sie die Datei Todos.svelte
öffnen und einen number
Typ unserem $alert
-Store zuweisen, erhalten Sie den folgenden Fehler:
Das liegt daran, dass wir, als wir unseren Alert Store in der stores.ts
Datei definiert haben mit:
export const alert = writable("Welcome to the To-Do list app!");
TypeScript den generischen Typ string
angenommen hat. Wenn wir darüber explizit sein wollten, könnten wir das Folgende tun:
export const alert = writable<string>("Welcome to the To-Do list app!");
Nun lassen Sie uns unseren localStore
Store generische Unterstützung hinzufügen. Denken Sie daran, dass wir den JsonValue
Typ definiert haben, um die Verwendung unserer localStore
Stores mit Werten zu verhindern, die nicht mit JSON.stringify()
gespeichert werden können. Jetzt möchten wir, dass die Verbraucher von localStore
in der Lage sind, den Typ der zu speichernden Daten anzugeben, aber statt mit einem beliebigen Typ zu arbeiten, sollten sie die JsonValue
-Bedingungen erfüllen. Wir werden das mit einer generischen Einschränkung spezifizieren, so:
export const localStore = <T extends JsonValue>(key: string, initial: T)
Wir definieren einen generischen Typ T
und spezifizieren, dass er mit dem JsonValue
Typ kompatibel sein muss. Dann verwenden wir den T
Typ entsprechend.
Unsere localStore.ts
Datei wird folgendermaßen aussehen – versuchen Sie es jetzt mit dem neuen Code in Ihrer Version:
// localStore.ts
import { writable } from "svelte/store";
import type { JsonValue } from "./types/json.type";
export const localStore = <T extends JsonValue>(key: string, initial: T) => {
// receives the key of the local storage and an initial value
const toString = (value: T) => JSON.stringify(value, null, 2); // helper function
const toObj = JSON.parse; // helper function
if (localStorage.getItem(key) === null) {
// item not present in local storage
localStorage.setItem(key, toString(initial)); // initialize local storage with initial value
}
const saved = toObj(localStorage.getItem(key)); // convert to object
const { subscribe, set, update } = writable<T>(saved); // create the underlying writable store
return {
subscribe,
set: (value: T) => {
localStorage.setItem(key, toString(value)); // save also to local storage as a string
return set(value);
},
update,
};
};
Und dank generischer Typenableitung weiß TypeScript bereits, dass unser $todos
Store ein Array von TodoType
enthalten sollte:
Ein weiteres Beispiel dafür, wenn wir explizit sein wollen, könnten wir es in der stores.ts
Datei tun, so:
const initialTodos: TodoType[] = [
{ id: 1, name: "Visit MDN web docs", completed: true },
{ id: 2, name: "Complete the Svelte Tutorial", completed: false },
];
export const todos = localStore<TodoType[]>("mdn-svelte-todo", initialTodos);
Das war unsere kurze Einführung in TypeScript Generika.
Der bisherige Code
Git
Um den Zustand des Codes zu sehen, wie er am Ende dieses Artikels aussehen sollte, greifen Sie mit Ihrer Kopie unseres Repos folgendermaßen darauf zu:
cd mdn-svelte-tutorial/08-next-steps
Oder laden Sie den gesamten Ordnerinhalt direkt herunter:
npx degit opensas/mdn-svelte-tutorial/08-next-steps
Erinnern Sie sich daran, npm install && npm run dev
auszuführen, um Ihre App im Entwicklungsmodus zu starten.
REPL
Wie bereits erwähnt, ist TypeScript noch nicht im REPL verfügbar.
Zusammenfassung
In diesem Artikel haben wir unsere To-Do-Listen-Applikation genommen und auf TypeScript portiert.
Wir haben zuerst über TypeScript gelernt und welche Vorteile es uns bieten kann. Dann haben wir gesehen, wie man ein neues Svelte-Projekt mit TypeScript-Unterstützung erstellt. Wir haben auch gesehen, wie man ein bestehendes Svelte-Projekt konvertiert, um TypeScript zu verwenden – unsere To-Do-Liste App.
Wir haben gelernt, wie man mit Visual Studio Code und der Svelte-Erweiterung arbeitet, um Funktionen wie Typüberprüfung und Autovervollständigung zu erhalten. Wir haben auch das svelte-check
-Tool verwendet, um TypeScript-Probleme von der Befehlszeile aus zu überprüfen.
Im nächsten Artikel lernen wir, wie wir unsere App kompilieren und in der Produktion bereitstellen. Wir werden auch sehen, welche Ressourcen online zur Verfügung stehen, um das Lernen von Svelte weiter voranzutreiben.