Machen Sie Ihren JavaScript-Code robust mit Flow

JavaScript war immer eine bedeutende Programmiersprache, da es die einzige Sprache ist, die zuverlässig im Browser ausgeführt wird. Die jüngsten Trends in der Frontend-Entwicklung sowie die auf Node.js basierende Backend-Entwicklung haben den Umfang und die Komplexität von JavaScript-Anwendungen weiter vorangetrieben. 

Große Anwendungen, die von großen Teams entwickelt wurden, können von der statischen Typprüfung profitieren, an der JavaScript fehlt. Flow wurde von Facebook entwickelt, um dieses Problem zu beheben. Es handelt sich um einen statischen Typ-Checker, der sich in Ihren Entwicklungsprozess einfügt, viele Probleme frühzeitig erkennt und Ihnen hilft, schnell voranzukommen.

Was ist Fluss??

Flow ist ein Tool, das Ihren mit Anmerkungen versehenen JavaScript-Code überprüft und verschiedene Probleme erkennt, die ohne es nur zur Laufzeit (oder schlimmer) erkannt würden, nicht Ihre Daten entdeckt und beschädigt haben). Hier ist ein kurzes Beispiel.

// @flow function getGreeting (name: string): string return 'Hi, $ name';  const http = erfordern ("http"); const greeting = getGreeting ("Gigi") const port = 8888 console.log ('Port $ port abhören ...') http.createServer (Funktion (Anfrage, Antwort) response.writeHead (200, "Content-Type) ":" text / plain "); response.write (Begrüßung); response.end ();). listen (port);

Fluss vs. TypScript

Bevor Sie in die Details von Flow eintauchen, lohnt es sich, sie mit anderen Alternativen zu vergleichen, insbesondere mit TypeScript. TypeScript ist eine strikte Obermenge von JavaScript, die von Microsoft entwickelt wurde. Jedes JavaScript-Programm ist auch ein TypeScript-Programm. 

TypeScript fügt optionale Typanmerkungen hinzu und dient insgesamt dem gleichen Zweck wie Flow. Es gibt jedoch einige wichtige Unterschiede. TypeScript ist eine separate Programmiersprache, die zu JavaScript kompiliert wird, während Flow-Annotationen entfernt werden müssen, um wieder gültiges JavaScript zu erhalten. 

TypeScript bietet großartige Tools und IDE-Unterstützung. Flow holt auf (z. B. hat JetBrains WebStorm eine native Flow-Integration).

Der wichtigste philosophische Unterschied besteht darin, dass Flow auf Soundness Wert legt. TypeScript 1.0 hat keine Nullfehler erkannt. TypeScript 2.0 mit strengen Nullprüfungen wurde in dieser Hinsicht bis auf Flow gemessen. In anderen Aspekten wie generischen Containern oder Typisierung ist TypeScript jedoch toleranter und lässt verschiedene Kategorien von Fehlern durch (nur die strukturelle Typisierung wird geprüft), nicht nominale Typisierung).

TypeScript als eigene Sprache fügt Konzepte und Sprachfunktionen wie Klassen, Schnittstellen, Sichtbarkeitsindikatoren (öffentlich, privat, schreibgeschützt) und Dekorateure hinzu. Diese Funktionen erleichtern das Verständnis und die Verwendung für Personen, die aus objektorientierten Mainstream-Sprachen wie C ++, Java und C # stammen..

Installation

Da Flow-Anmerkungen kein Standard-JavaScript sind, müssen sie vor der Bereitstellung Ihrer Anwendung entfernt werden. So installieren Sie Fließ- und Fließentfernungstypen über Garn: garne add --dev flow-bin flow-remove-types

Sie können Ihrer package.json-Datei einige Skripts hinzufügen, um den Prozess zu automatisieren:

 "scripts": "build": "flow-remove-types src / -d lib /", "prepublish": "gar run build build" 

Sie sollten das Prepublish-Skript ausführen, bevor Sie Ihren Code in der npm-Registry veröffentlichen.

Weitere Installationsoptionen (z. B. npm oder babel) finden Sie im Flow-Installationshandbuch.

Um die Installation abzuschließen, geben Sie Folgendes ein: Fadenlauffluss init

Dadurch wird die erforderliche .flowconfig-Datei erstellt.

Geben Sie System ein

Flow hat zwei wichtige Ziele: Präzision und Geschwindigkeit. Das Typsystem wurde entwickelt, um diese Ziele zu unterstützen.

Präzision

Präzision wird durch Analyse der Interaktion des Codes mit annotierten oder abgeleiteten Typen erzielt. Jede Nichtübereinstimmung führt zu einem Typfehler. Beschriftete Typen unterstützen die nominelle Typisierung. Dies bedeutet, dass zwei verschiedene Typen mit denselben Attributen voneinander unterschieden werden und nicht ersetzt werden können. Der Typ einer Variablen wird als Satz von Laufzeitwerten definiert, die die Variable erhalten kann. 

Geschwindigkeit

Der Fluss ist schnell durch eine Kombination aus Modularität und verteilter Verarbeitung. Dateien werden parallel analysiert, und die Ergebnisse werden später über einen effizienten gemeinsam genutzten Speicher zusammengeführt, um eine vollständige Programmtypüberprüfung durchzuführen.

Unterstützte Typen

Flow unterstützt viele Arten. Neben primitiven Typen unterstützt es auch Folgendes:

  • Objekt
  • Array
  • Irgendein
  • Könnte sein
  • Variable
  • Tupel
  • Klasse
  • Schnittstelle
  • Generisch

Geben Sie Anmerkungen ein

Mit Flow können Sie Typen deklarieren sowie Variablen und Parameter auf ausgewählte Werte einschränken:

Typ Two2Four = 2 | 3 | 4 Funktion doubleIt (Nummer: Two2Four) return number * 2 console.log (doubleIt (3)) Ausgabe: 6 

Wenn Sie den gültigen Bereich überschreiten, erhalten Sie eine Fehlermeldung:

console.log (doubleIt (3)) Ausgabe: Fehler: src / main.js: 30 30: console.log (doubleIt (5)) // Fehlernummer. Dieser Typ ist mit dem erwarteten Param-Typ 24 nicht kompatibel: function doubleIt (number: Two2Four) ^^^^^^^^ number enum Found 1 error 

Sie können auch komplexe Typen definieren, einschließlich Untertypen. Im folgenden Codebeispiel ist der Typ Warrior ein Subtyp von Person. Dies bedeutet, dass es in Ordnung ist, einen Krieger als Person aus der Liste zurückzugeben kämpfen() Funktion. Die Rückgabe von null ist jedoch verboten.

Typ Person = Name: String, Alter: Nummer Typ Warrior = Name: String, Alter: Anzahl, Stärke: Nummer let redWolf: Warrior = Name: "Red Wolf", Alter: 24, Stärke: 10 let skullCrusher: Warrior = Name: "Skull Crusher", Alter: 27, Stärke: 11 Funktionskampf (w1: Warrior, w2: Warrior): Person if (w1.stärke> w2.stärke) return w1 if ( w2.strength> w1.strength) return w2 return null Ausgabe: Gefunden 1 Fehler $ flow Fehler: src / main.js: 47 47: return null ^^^^ null. Dieser Typ ist nicht mit dem erwarteten Rückgabetyp 39 kompatibel: Funktionskampf (w1: Krieger, w2: Krieger): Person ^^^^^^ Objekttyp Fehler gefunden 

Um dies zu beheben, kehren wir den jüngeren Krieger zurück, wenn beide Krieger die gleiche Stärke haben:

Funktionskampf (w1: Krieger, w2: Krieger): Person if (w1.stärke> w2.stärke) return w1 if (w2.stärke> w1.stärke) return w2 return (w1.age < w2.age ? w1 : w2)  let winner = fight(redWolf, skullCrusher) console.log(winner.name) Output: Skull Crusher 

Flow ermöglicht eine noch präzisere Steuerung über Klassenerweiterung, Invarianz, Kovarianz und Kontravarianz. Lesen Sie die Flow-Dokumentation zur Abweichung.

Aufbau

Flow verwendet die .flowconfig-Konfigurationsdatei im Stammverzeichnis Ihrer Projekte. Diese Datei enthält mehrere Abschnitte, in denen Sie konfigurieren können, welche Dateien Flow prüfen soll, und welche Aspekte er ausführt. 

Umfassen

Das [umfassen] Abschnitt steuert, welche Verzeichnisse und Dateien geprüft werden sollen. Das Stammverzeichnis ist standardmäßig immer enthalten. Die Wege in der [umfassen] Abschnitte sind relativ. Ein einzelner Stern ist ein Platzhalter für Dateinamen, Erweiterungen oder Verzeichnisnamen. Zwei Sterne sind ein Platzhalter für alle Verzeichnisse. Hier ist ein Beispiel [umfassen] Sektion:

[include]… /externalFile.js… / externalDir /… /otherProject/*.js… / otherProject / ** / coolStuff /

Ignorieren

Das [ignorieren] Abschnitt ist die Ergänzung zu [umfassen]. Dateien und Verzeichnisse, die Sie hier angeben, werden von flow nicht geprüft. Seltsamerweise verwendet es eine andere Syntax (reguläre OCaml-Ausdrücke) und erfordert absolute Pfade. Dies zu ändern, steht auf der Roadmap des Flow-Teams.

Bis dahin müssen Sie beachten, dass der Include-Abschnitt zuerst verarbeitet wird, gefolgt vom Ignorier-Abschnitt. Wenn Sie dasselbe Verzeichnis und / oder dieselbe Datei einschließen und ignorieren, wird dies ignoriert. Um das Problem des absoluten Pfads zu beheben, wird üblicherweise jeder Zeile ein vorangestelltes Zeichen vorangestellt .*. Wenn Sie Verzeichnisse oder Dateien unter dem Stammverzeichnis ignorieren möchten, können Sie das verwenden  Platzhalter statt .*. Hier ist ein Beispiel [ignorieren] Sektion:

[ignorieren]. * / __ testet __ /. *. * / src / \ (foo \ | bar \) /.*. * \. ignoriert \ .js /ignore_me.js

Libs

Jede nicht triviale JavaScript-Anwendung verwendet viele Bibliotheken von Drittanbietern. Flow kann überprüfen, wie Ihre Anwendung diese Bibliotheken verwendet, wenn Sie spezielle libdef-Dateien bereitstellen, die Typinformationen zu diesen Bibliotheken enthalten. 

Flow durchsucht automatisch das "flow-typed" -Unterverzeichnis Ihres Projekts nach libdef-Dateien. Sie können jedoch auch den Pfad der libdef-Dateien im Abschnitt [libs] angeben. Dies ist nützlich, wenn Sie ein zentrales Repository mit libdef-Dateien verwalten, die von mehreren Projekten verwendet werden.

Das Importieren vorhandener Typdefinitionen und das Erstellen eigener, wenn die Zielbibliothek keine eigenen Typdefinitionen bereitstellt, ist ziemlich einfach. Sehen:

  • Ablaufdokumentation: Bibliotheksdefinitionen
  • Ablaufdokumentation: Erstellen von Bibliotheksdefinitionen
  • GitHub: Bibliotheksdefinitionen importieren und verwenden

Lints

Flow verfügt über mehrere Flusenregeln, die Sie steuern und festlegen können, wie sie behandelt werden sollen. Sie können die Regeln über die Befehlszeile, in Codekommentaren oder in der Befehlszeile konfigurieren [Lints] Abschnitt Ihrer Konfigurationsdatei. Ich werde im nächsten Abschnitt über das Flusen sprechen [Lints] Sektion:

[lints] all = warn untyped-type-import = Fehler sketchy-null-bool = aus

Optionen

Das [Optionen] In diesem Abschnitt erfahren Sie, wie Flow sich in einer Reihe von Fällen verhält, in denen es keinen eigenen Abschnitt gibt. Daher sind sie alle in Gruppen zusammengefasst.

Es gibt zu viele Optionen, um sie alle hier aufzulisten. Einige der interessanteren sind:

  • alles: Auf true setzen, um alle Dateien zu überprüfen, nicht nur die mit @flow
  • Emoji: Auf true setzen, um Emojis zu Statusnachrichten hinzuzufügen
  • module.use_strict: Setzen Sie den Wert auf "true", wenn Sie einen Transpiler verwenden, der "use strict;"
  • suppress_comment: ein regulärer Ausdruck, der einen Kommentar definiert, um Flussfehler in der folgenden Zeile zu unterdrücken (nützlich für laufenden Code)

Überprüfen Sie alle Optionen in der Flow-Anleitung zum Konfigurieren von Optionen.

Ausführung

Flow und sein Konfigurationsdateiformat entwickeln sich weiter. Das [Ausführung] In diesem Abschnitt können Sie angeben, für welche Version von Flow die Konfigurationsdatei konzipiert ist, um verwirrende Fehler zu vermeiden.

Wenn die Version von Flow nicht mit der konfigurierten Version übereinstimmt, zeigt Flow eine Fehlermeldung an.

Es gibt einige Möglichkeiten, die unterstützten Versionen anzugeben:

[version] 0.22.0 [version]> = 0.13.0 <0.14.0 [version] ^1.2.3 

Die Caret-Version behält die erste Nicht-Null-Komponente der Version bei. So ^ 1.2.3 erweitert sich auf den Bereich> = 1.2.3 < 2.0.0, and 0,4,5 erweitert sich auf den Bereich> = 0,4,5 < 0.5.0.

Verwenden des Flusses von der Befehlszeile aus

Flow ist ein Client-Server-Programm. Ein Flow-Server muss ausgeführt werden, und der Client stellt eine Verbindung zu ihm her (oder startet ihn, falls er nicht läuft). Die Flow-CLI verfügt über viele Befehle und Optionen, die für Wartungs- und Introspektionszwecke sowie für das vorübergehende Überschreiben der Konfiguration von .flowconfig nützlich sind.

Tippen flow --hilfe Zeigt alle Befehle und Optionen an. Um Hilfe zu einem bestimmten Befehl zu erhalten, geben Sie Folgendes ein fließen --Hilfe. Zum Beispiel:

$ flow ast --help Verwendung: flow ast [OPTION]… [DATEI], z. fluss ast foo.js oder fluss ast < foo.js --from Specify client (for use by editor plugins) --help This list of options --pretty Pretty-print JSON output --tokens Include a list of syntax tokens in the output --type Type of input file (js or json) 

Wichtige Befehle sind:

  • drin: Erzeugen Sie eine leere .flowconfig-Datei
  • prüfen: Führen Sie eine vollständige Flussprüfung durch und drucken Sie die Ergebnisse 
  • ls: Anzeigen von für Flow sichtbaren Dateien
  • Status (Standard): Aktuelle Flow-Fehler vom Flow-Server anzeigen
  • vorschlagen: schlägt Typen für die Zieldatei vor

Mit Fluss flushen

Flow verfügt über ein Linting-Framework, das wie zuvor über die .flowconfig-Datei, über Befehlszeilenargumente oder in Codedateien mithilfe von flowlint-Kommentaren konfiguriert werden kann. Alle Konfigurationsmethoden bestehen aus einer Liste von Schlüssel-Wert-Paaren, bei denen der Schlüssel eine Regel ist und der Wert der Schweregrad ist. 

Regeln

Derzeit gibt es drei Regeln: alle, nicht typisierter Import und sketchy-null. Die Regel "Alle" ist in der Regel die Standardbehandlung für Fehler, für die keine spezifischere Regel gilt. Die Regel "Nicht typisierter Import" wird aufgerufen, wenn Sie einen Typ aus einer nicht typisierten Datei importieren. Die "Skizzieren-Null" -Regel wird aufgerufen, wenn Sie die Existenz eines Werts prüfen, der falsch oder null sein kann. Es gibt detailliertere Regeln für:

  • Sketchy-Null-Bool
  • Skizzierte-Null-Nummer
  • Skizzierte-Null-Zeichenfolge
  • skizzenhaft-null gemischt

Schweregrad

Es gibt auch drei Schweregrade: Aus, Warnung und Fehler. Wie Sie sich vorstellen können, überspringt "off" die Typüberprüfung. "Warn" gibt Warnungen aus, die nicht dazu führen, dass die Typüberprüfung beendet wird und standardmäßig nicht in der CLI-Ausgabe angezeigt wird (Sie können sie mit sehen --Include-Warnungen) und "error" wird wie Flussfehler behandelt und bewirkt, dass die Typprüfung beendet und eine Fehlermeldung angezeigt wird.

Linting mit Befehlszeilenargumenten

Verwenden Sie die --Lints Befehlszeilenargument zur Angabe mehrerer Flusenregeln. Zum Beispiel:

flow --lints "all = warn, untyped-type-import = error, sketchy-null-bool = off"

Linting With flowlint Kommentare

Es gibt drei Arten von Kommentaren: flowlint, flowlint-line und flowlint-next-line.

Der "flowlint" -Kommentar wendet einen Satz von Regeln in einem Block an, bis er durch einen übereinstimmenden Kommentar überschrieben wird:

import type // flowlint untyped-type-import: off Foo, Bar, Baz, // flowlint untyped-type-import: error from './untyped.js'; 

Wenn kein passender Kommentar vorhanden ist, gelten die Einstellungen einfach bis zum Ende der Datei.

Die "flowlint-line" gilt nur für die aktuelle Zeile:  

Funktion (x:? boolean) if (x) // flowlint-line sketchy-null-bool: off… else … 

Die "flowlint-next-line" gilt für die Zeile nach dem Kommentar:

function (x:? boolean) // flowlint-next-line sketchy-null-bool: off if (x) … else … 

Fazit

Große JavaScript-Projekte, die von großen Teams entwickelt wurden, können von der Überprüfung statischer Typen erheblich profitieren. Es gibt verschiedene Lösungen, um die statische Typüberprüfung in eine JavaScript-Codebase einzuführen. 

JavaScript wächst auf vielfältige Weise im Web. Es ist nicht ohne Lernkurven und es gibt viele Frameworks und Bibliotheken, die Sie beschäftigen, wie Sie sehen können. Wenn Sie nach zusätzlichen Ressourcen suchen, um zu studieren oder in Ihrer Arbeit zu verwenden, schauen Sie nach, was wir auf dem Envato-Marktplatz zur Verfügung haben.

Facebooks Flow ist eine aktuelle und robuste Lösung mit hervorragender Abdeckung, Werkzeugausstattung und Dokumentation. Probieren Sie es aus, wenn Sie eine große JavaScript-Codebasis haben.