Svelte ist eines der neueren JavaScript-Frameworks und seine Popularität nimmt rasant zu. Es ist ein Template-basiertes Framework, das jedoch beliebige JavaScript-Code innerhalb der Template-Bindungen erlaubt; es hat eine hervorragende Reaktivitäts-Story, die einfach, flexibel und effektiv ist; und als Ahead-of-Time (AOT) kompiliertes Framework hat es unglaublich beeindruckende Leistung und Bundle-Größen. Dieser Beitrag konzentriert sich auf die Konfiguration von TypeScript in Svelte-Templates. Wenn Sie neu bei Svelte sind, empfehle ich Ihnen, das Einführungs-Tutorial und die Dokumentation zu lesen.
Wenn Sie den Code nachverfolgen möchten (oder wenn Sie das, was Sie in Ihrem eigenen Projekt vermissen könnten, debuggen möchten), können Sie das Repository klonen. Ich habe Branches eingerichtet, um die verschiedenen Teile zu demonstrieren, die ich behandeln werde.
Hinweis: Während wir Svelte und TypeScript manuell integrieren werden, könnten Sie in Erwägung ziehen, die offizielle Svelte-Vorlage zu verwenden, die dasselbe tut, wenn Sie ein Greenfield-Projekt starten. In jedem Fall deckt dieser Beitrag eine TypeScript-Konfiguration ab, die auch dann relevant ist, wenn Sie die Vorlage verwenden.
Grundlegende TypeScript und Svelte Einrichtung
Betrachten wir eine grundlegende Einrichtung. Wenn Sie zum Branch initial-setup im Repository gehen, finden Sie dort ein nacktes Svelte-Projekt mit TypeScript. Um klar zu sein, TypeScript funktioniert nur in eigenständigen .ts-Dateien. Es ist in keiner Weise in Svelte integriert. Die Erreichung der TypeScript-Integration ist der Zweck dieses Beitrags.
Ich werde einige Teile durchgehen, die Svelte und TypeScript zum Laufen bringen, hauptsächlich weil ich sie gleich ändern werde, um TypeScript-Unterstützung für Svelte-Templates hinzuzufügen.
Zuerst habe ich eine tsconfig.json-Datei
{
"compilerOptions": {
"module": "esNext",
"target": "esnext",
"moduleResolution": "node"
},
"exclude": ["./node_modules"]
}
Diese Datei teilt TypeScript mit, dass ich modernes JavaScript verwenden möchte, Node-Auflösung nutzen und eine node_modules von der Kompilierung ausschließen möchte.
Dann habe ich in typings/index.d.ts Folgendes:
declare module "*.svelte" {
const value: any;
export default value;
}
Dies ermöglicht es TypeScript, mit Svelte zu koexistieren. Ohne dies würde TypeScript Fehler ausgeben, sobald eine Svelte-Datei mit einer Importanweisung geladen wird. Schließlich müssen wir Webpack mitteilen, unsere Svelte-Dateien zu verarbeiten, was wir mit dieser Regel in webpack.config.js tun:
{
test: /\.(html|svelte)$/,
use: [
{ loader: "babel-loader" },
{
loader: "svelte-loader",
options: {
emitCss: true,
},
},
],
}
Das alles ist die grundlegende Einrichtung für ein Projekt, das Svelte-Komponenten und TypeScript-Dateien verwendet. Um zu bestätigen, dass alles kompiliert, öffnen Sie ein paar Terminals und führen Sie npm start in einem aus, was einen Webpack-Watch startet, und npm run tscw in dem anderen, um eine TypeScript-Watch-Aufgabe zu starten. Hoffentlich laufen beide ohne Fehler. Um wirklich zu überprüfen, ob die TypeScript-Prüfung läuft, können Sie Folgendes ändern:
let x: number = 12;
...in index.ts zu
let x: number = "12";
...und den Fehler im TypeScript-Watch sehen. Wenn Sie dies tatsächlich ausführen möchten, können Sie node server in einem dritten Terminal ausführen (ich empfehle iTerm2, das es Ihnen ermöglicht, diese Terminals in Tabs im selben Fenster auszuführen) und dann localhost:3001 aufrufen.
TypeScript zu Svelte hinzufügen
Fügen wir TypeScript direkt zu unserer Svelte-Komponente hinzu und sehen wir dann, welche Konfigurationsänderungen wir vornehmen müssen, um sie zum Laufen zu bringen. Gehen Sie zuerst zu Helper.svelte und fügen Sie lang="ts" zum Skript-Tag hinzu. Das teilt Svelte mit, dass sich TypeScript im Skript befindet. Lassen Sie uns nun tatsächlich etwas TypeScript hinzufügen. Ändern wir die val-Prop, um sie als Zahl zu prüfen, über export let val: number;. Die gesamte Komponente sieht jetzt so aus:
<script lang="ts">
export let val: number;
</script>
<h1>Value is: {val}</h1>
Unser Webpack-Fenster sollte jetzt einen Fehler anzeigen, aber das ist zu erwarten.

Wir müssen dem Svelte-Loader mitteilen, wie er mit TypeScript umgehen soll. Lassen Sie uns Folgendes installieren:
npm i svelte-preprocess svelte-check --save
Gehen wir nun zu unserer Webpack-Konfigurationsdatei und holen uns svelte-preprocess
const sveltePreprocess = require("svelte-preprocess");
...und fügen Sie es unserem Svelte-Loader hinzu:
{
test: /\.(html|svelte)$/,
use: [
{ loader: "babel-loader" },
{
loader: "svelte-loader",
options: {
emitCss: true,
preprocess: sveltePreprocess({})
},
},
],
}
Okay, lassen Sie uns den Webpack-Prozess neu starten, und er sollte kompilieren.
Prüfung hinzufügen
Bisher kompiliert das, was wir haben, aber es prüft nicht. Wenn wir ungültigen Code in einer Svelte-Komponente haben, möchten wir, dass dies einen Fehler generiert. Gehen wir also zu App.svelte, fügen Sie dasselbe lang="ts" zum Skript-Tag hinzu und übergeben Sie dann einen ungültigen Wert für die val-Prop, wie hier:
<Helper val={"3"} />
Wenn wir in unserem TypeScript-Fenster nachsehen, gibt es keine Fehler, aber es sollte welche geben. Es stellt sich heraus, dass wir unsere Svelte-Templates nicht mit dem normalen tsc-Compiler typisieren, sondern mit dem svelte-check-Dienstprogramm, das wir zuvor installiert haben. Lassen Sie uns unseren TypeScript-Watch stoppen und in diesem Terminal npm run svelte-check ausführen. Das startet den svelte-check-Prozess im Watch-Modus, und wir sollten den erwarteten Fehler sehen.

Entfernen Sie nun die Anführungszeichen um die 3, und der Fehler sollte verschwinden.

Klasse!
In der Praxis möchten wir, dass sowohl svelte-check als auch tsc gleichzeitig laufen, damit wir beide Fehler sowohl in unseren TypeScript-Dateien als auch in unseren Svelte-Templates erkennen. Es gibt eine Reihe von Dienstprogrammen auf npm, die dies ermöglichen, oder wir können iTerm2 verwenden, das mehrere Terminals im selben Fenster aufteilen kann. Ich verwende es hier, um den Server, den Webpack-Build, den tsc-Build und den svelte-check-Build auszuführen.

Diese Einrichtung befindet sich im Branch basic-checking des Repos.
Fehlende Props abfangen
Es gibt immer noch ein Problem, das wir lösen müssen. Wenn wir eine erforderliche Prop weglassen, wie die val-Prop, die wir gerade betrachtet haben, erhalten wir immer noch keinen Fehler, aber wir sollten, da wir ihr keinen Standardwert in Helper.svelte zugewiesen haben und sie daher erforderlich ist.
<Helper /> // missing `val` prop
Um TypeScript mitzuteilen, dies als Fehler zu melden, gehen wir zurück zu unserer tsconfig und fügen zwei neue Werte hinzu:
"strict": true,
"noImplicitAny": false
Die erste aktiviert eine Reihe von TypeScript-Prüfungen, die standardmäßig deaktiviert sind. Die zweite, noImplicitAny, schaltet eine dieser strengen Prüfungen ab. Ohne die zweite Zeile wird jede Variable, der ein Typ fehlt (die implizit als any typisiert ist), nun als Fehler gemeldet (kein implizites any, verstanden?)
Die Meinungen gehen weit auseinander, ob noImplicitAny auf true gesetzt werden sollte. Ich persönlich halte es für zu streng, aber viele Leute sind anderer Meinung. Experimentieren Sie und kommen Sie zu Ihrer eigenen Schlussfolgerung.
Wie auch immer, mit dieser neuen Konfiguration sollten wir unseren svelte-check-Task neu starten und den erwarteten Fehler sehen können.

Diese Einrichtung befindet sich im Branch better-checking des Repos.
Verschiedenes
Eine Sache, die man beachten sollte, ist, dass der Mechanismus von TypeScript zum Erkennen falscher Eigenschaften sofort und irreversibel für eine Komponente deaktiviert wird, wenn diese Komponente jemals $$props oder $$restProps referenziert. Wenn Sie beispielsweise eine nicht deklarierte Prop wie junk an die Helper-Komponente übergeben, erhalten Sie einen Fehler, wie erwartet, da diese Komponente keine junk-Eigenschaft hat. Aber dieser Fehler würde sofort verschwinden, wenn die Helper-Komponente $$props oder $$restProps referenzieren würde. Das erste erlaubt Ihnen den dynamischen Zugriff auf jede Prop, ohne dass eine explizite Deklaration dafür vorhanden ist, während $$restProps für den dynamischen Zugriff auf nicht deklarierte Props dient.
Das ergibt Sinn, wenn man darüber nachdenkt. Der Zweck dieser Konstrukte ist der dynamische Zugriff auf eine Eigenschaft im laufenden Betrieb, normalerweise für eine Art Metaprogrammierung oder um Attribute willkürlich an ein HTML-Element zu übergeben, was bei UI-Bibliotheken üblich ist. Die Existenz eines von beiden impliziert einen willkürlichen Zugriff auf eine Komponente, die möglicherweise nicht deklariert wurde.
Es gibt noch eine weitere häufige Verwendung von $$props, und zwar den Zugriff auf Props, die als reserviertes Wort deklariert sind. class ist ein gängiges Beispiel dafür. Zum Beispiel:
const className = $$props.class;
...da
export let class = "";
...nicht gültig ist. class ist ein reserviertes Wort in JavaScript, aber in diesem speziellen Fall gibt es eine Umgehung. Das Folgende ist auch eine gültige Methode, um dieselbe Prop zu deklarieren – danke an Rich Harris für seine Hilfe dabei.
let className;
export { className as class };
Wenn Ihre einzige Verwendung von $$props darin besteht, auf eine Prop zuzugreifen, deren Name reserviert ist, können Sie diese Alternative verwenden und eine bessere Typenprüfung für Ihre Komponente beibehalten.
Abschließende Gedanken
Svelte ist eines der vielversprechendsten, produktivsten und ehrlich gesagt unterhaltsamsten JavaScript-Frameworks, mit denen ich gearbeitet habe. Die relative Leichtigkeit, mit der TypeScript hinzugefügt werden kann, ist das Tüpfelchen auf dem i. Wenn TypeScript Fehler frühzeitig für Sie erkennt, kann dies zu einer echten Produktivitätssteigerung führen. Hoffentlich war dieser Beitrag hilfreich, um dies zu erreichen.
Warum verwendest du nicht das offizielle svelte-typescript-Template-Repository? Du kannst einfach npx degit sveltejs/template my-svelte-project normal ausführen und dann node scripts/setupTypeScript.js ausführen, das ist alles, was benötigt wird.
Hey, danke dafür. Das kannte ich nicht, aber ich werde sehen, ob ich eine Notiz zu diesem Artikel hinzufüge. Abgesehen davon ist der Inhalt hier immer noch wertvoll für diejenigen, die TS-Unterstützung zu einem bestehenden Projekt hinzufügen möchten.
Vielen Dank für dieses Tutorial. Sie haben mir gerade den Job gerettet!
Danke. Sie bieten eine andere Methode als das offizielle Repository. Das offizielle verwendet tsc und dieses hier verwendet Babel. Es hat mir beim Aufbau unseres Repos geholfen. Es scheint, dass tsconfig.json auch für Babel immer noch benötigt wird.
Sie können
$$restPropstypisieren, wenn Sie eine separate.d.ts-Datei mit demselben Namen wie Ihre Komponente erstellen.Siehe https://github.com/bestguy/sveltestrap/blob/master/src/Card.d.ts als Beispiel in einer beliebten Bibliothek.