Maak uw JavaScript-code Robuust met stroom

JavaScript was altijd een belangrijke programmeertaal, omdat dit de enige taal is die betrouwbaar in de browser draait. Recente trends in front-end development en op Node.js gebaseerde back-end ontwikkeling hebben de schaal en complexiteit van JavaScript-applicaties naar een hoger niveau getild.. 

Grote applicaties ontwikkeld door grote teams kunnen profiteren van statische typecontrole, die vanille JavaScript mist. Flow is ontwikkeld door Facebook om dit probleem aan te pakken. Het is een statische type checker die integreert in uw ontwikkelingsproces, veel problemen vroeg opvangt en u helpt om snel te handelen.

Wat is Flow?

Flow is een tool die je geannoteerde JavaScript-code controleert en verschillende problemen detecteert die zonder het alleen tijdens runtime zouden worden ontdekt (of erger), niet uw gegevens hebben ontdekt en beschadigd). Hier is een snel voorbeeld.

// @flow-functie getGreeting (naam: string): tekenreeks return 'Hallo, $ naam';  const http = require ("http"); const groet = getGreeting ("Gigi") const port = 8888 console.log ('Luisteren op poort $ poort ...') http.createServer (functie (verzoek, antwoord) response.writeHead (200, "Content-Type ":" text / plain "); response.write (groet); response.end ();). listen (poort);

Flow versus TypeScript

Voordat je de subtiele details van Flow induikt, is het de moeite waard om het te vergelijken met andere alternatieven, en in het bijzonder TypeScript. TypeScript is een strikte superset van JavaScript ontwikkeld door Microsoft. Elk JavaScript-programma is ook een TypeScript-programma. 

TypeScript voegt optionele type-annotaties toe en heeft over het algemeen hetzelfde doel als Flow. Er zijn echter enkele belangrijke verschillen. TypeScript is een afzonderlijke programmeertaal die is gecompileerd naar JavaScript, terwijl Flow-annotaties moeten worden verwijderd om terug te gaan naar geldig JavaScript. 

TypeScript heeft geweldige tool- en IDE-ondersteuning. Flow is een inhaalslag (bijvoorbeeld JetBrains WebStorm heeft native Flow-integratie).

Het belangrijkste filosofische verschil is dat Flow de nadruk legt op degelijkheid. TypeScript 1.0 heeft geen null-fouten aangetroffen; TypeScript 2.0 met strikte nulcontroles gemeten tot Flow in dit opzicht. Maar in andere aspecten, zoals generieke containers of typen, is TypeScript meer permissief en laat het verschillende categorieën fouten door (alleen structureel typen wordt gecontroleerd), niet nominaal typen).

TypeScript als zijn eigen taal voegt concepten en taalfuncties toe, zoals klassen, interfaces, zichtbaarheidsindicatoren (openbaar, privé, alleen-lezen) en decorateurs. Deze functies maken het gemakkelijker te begrijpen en te gebruiken voor mensen die afkomstig zijn van standaard objectgeoriënteerde talen zoals C ++, Java en C #.

Installatie

Aangezien Flow-annotaties geen standaard JavaScript zijn, moeten ze worden verwijderd voordat u uw toepassing implementeert. Hier is hoe u flow en flow-remove-types installeert via garen: garen toevoegen --dev flow-bin flow-remove-types

U kunt een paar scripts toevoegen aan uw package.json-bestand om het proces te automatiseren:

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

U moet het prepublish-script uitvoeren voordat u uw code publiceert naar het npm-register.

Voor andere installatieopties (bijvoorbeeld met behulp van npm of babel), raadpleegt u de Flow installatiehandleiding.

Typ de volgende stappen om de installatie te voltooien: garen lopen stroom init

Hiermee wordt het vereiste .flowconfig-bestand gemaakt.

Type Systeem

Flow heeft twee belangrijke doelen: precisie en snelheid. Het type systeem is ontworpen om deze doelen te ondersteunen.

precisie

Precisie wordt bereikt door te analyseren hoe de code interageert met typen, hetzij geannoteerd of afgeleid. Elke verkeerde combinatie veroorzaakt een typefout. Geannoteerde typen ondersteunen nominaal typen, wat betekent dat twee verschillende typen met dezelfde kenmerken van elkaar worden onderscheiden en niet kunnen worden vervangen. Het type van een variabele wordt gedefinieerd als de set runtime-waarden die de variabele kan ontvangen. 

Snelheid

Flow is snel dankzij een combinatie van modulariteit en gedistribueerde verwerking. Bestanden worden parallel geanalyseerd, en de resultaten worden later samengevoegd via efficiënt gedeeld geheugen om het controleren op het volledige programmatype te voltooien.

Ondersteunde typen

Flow ondersteunt vele soorten. Naast de primitieve typen ondersteunt het ook het volgende:

  • Voorwerp
  • reeks
  • Ieder
  • Kan zijn
  • veranderlijk
  • tupel
  • Klasse
  • Interface
  • Algemeen

Typ Annotaties

Met Flow kunt u typen declareren en variabelen en parameters beperken tot geselecteerde waarden:

typ Two2Four = 2 | 3 | 4 functie doubleIt (nummer: Two2Four) retournummer * 2 console.log (doubleIt (3)) Uitvoer: 6 

Als u het geldige bereik overschrijdt, krijgt u een foutmelding:

console.log (doubleIt (3)) Uitvoer: Fout: src / main.js: 30 30: console.log (doubleIt (5)) // fout ^ nummer. Dit type is niet compatibel met het verwachte param type 24: function doubleIt (number: Two2Four) ^^^^^^^^ nummer enum Gevonden 1 fout 

U kunt ook complexe typen definiëren, inclusief subtypen. In het volgende codevoorbeeld is het Warrior-type een subtype Person. Dit betekent dat het OK is om een ​​Warrior terug te brengen als een Persoon uit de strijd() functie. Retourneren van null is echter verboden.

type Person = naam: string, age: number type Warrior = naam: string, age: number, strength: number let redWolf: Warrior = name: "Red Wolf", leeftijd: 24, sterkte: 10 let skullCrusher: Warrior = name: "Skull Crusher", age: 27, strength: 11 function fight (w1: Warrior, w2: Warrior): Person if (w1.strength> w2.strength) return w1 if ( w2.strength> w1.strength) return w2 return null Uitgang: Gevonden 1 fout $ flow Fout: src / main.js: 47 47: return null ^^^^ null. Dit type is niet compatibel met het verwachte retourtype van 39: function fight (w1: Warrior, w2: Warrior): Person ^^^^^^ objecttype Found 1 error 

Om het te repareren, laten we de jongere krijger terugbrengen als beide krijgers dezelfde sterkte hebben:

function fight (w1: Warrior, w2: Warrior): Person if (w1.strength> w2.strength) return w1 if (w2.strength> w1.strength) return w2 return (w1.age < w2.age ? w1 : w2)  let winner = fight(redWolf, skullCrusher) console.log(winner.name) Output: Skull Crusher 

Flow maakt nog nauwkeurigere besturing mogelijk via klasse-uitbreiding, invariantie, co-variantie en contra-variantie. Bekijk de Flow-documentatie over variantie.

Configuratie

Flow gebruikt het .flowconfig-configuratiebestand in de hoofdmap van uw projecten. Dit bestand bevat verschillende secties waarmee u kunt configureren welke bestanden Flow moet controleren en de vele aspecten van de werking ervan. 

omvatten

De [Omvat] sectie bepaalt welke mappen en bestanden moeten worden gecontroleerd. De hoofdmap is altijd standaard inbegrepen. De paden in de [Omvat] secties zijn relatief. Een enkele ster is een jokerteken voor elke bestandsnaam, extensie of mapnaam. Twee sterren zijn een wildcard voor elke mapdiepte. Hier is een voorbeeld [Omvat] sectie:

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

Negeren

De [negeren] sectie is de aanvulling op [Omvat]. Bestanden en mappen die u hier opgeeft, worden niet gecontroleerd door flow. Vreemd genoeg gebruikt het een andere syntaxis (OCaml reguliere expressies) en vereist het absolute paden. Dit wijzigen staat op de routekaart van het Flow-team.

Onthoud tot die tijd dat de include-sectie eerst wordt verwerkt, gevolgd door de negeersectie. Als u dezelfde map en / of een bestand opneemt en negeert, wordt deze genegeerd. Om het probleem met het absolute pad aan te pakken, is het gebruikelijk om elke regel vooraf te kiezen .*. Als u mappen of bestanden onder de root wilt negeren, kunt u de  tijdelijke aanduiding in plaats van .*. Hier is een voorbeeld [negeren] sectie:

[negeren]. * / __ tests __ /. *. * / src / \ (foo \ | bar \) /.*. * \. negeer \ .js /ignore_me.js

libs

Elke niet-triviale JavaScript-toepassing gebruikt veel externe bibliotheken. Flow kan controleren hoe uw toepassing deze bibliotheken gebruikt als u speciale libdef-bestanden met type-informatie over deze bibliotheken opgeeft. 

Flow scant automatisch de "flow-typed" submap van uw project voor libdef-bestanden, maar u kunt ook het pad van libdef-bestanden in de sectie [libs] opgeven. Dit is handig als u een centrale opslagplaats van libdef-bestanden bij meerdere projecten onderhoudt.

Het importeren van bestaande typedefinities en het maken van uw eigen definities als de doelbibliotheek geen eigen typedefinities levert, is vrij eenvoudig. Zien:

  • Flow-documentatie: bibliotheekdefinities
  • Stroomdocumentatie: bibliotheekdefinities maken
  • GitHub: Bibliotheekdefinities importeren en gebruiken

Lints

Flow heeft verschillende lintregels die u kunt regelen en bepalen hoe u ze moet behandelen. U kunt de regels configureren vanaf de opdrachtregel, in codeopmerkingen of in de [Lints] sectie van uw configuratiebestand. Ik zal het pluizen bespreken in de volgende sectie, maar hier is hoe het te configureren met behulp van de [Lints] sectie:

[lints] all = warn untyped-type-import = error sketchy-null-bool = off

opties

De [Opties] In dit gedeelte kun je Flow vertellen hoe je je moet gedragen in verschillende gevallen die hun eigen sectie niet verdienen, dus ze zijn allemaal gegroepeerd.

Er zijn te veel opties om ze allemaal hier op te sommen. Enkele van de interessantere zijn:

  • allemaal: stel in op true om alle bestanden te controleren, niet alleen die met @flow
  • emoji: stel in op true om emoji's toe te voegen aan statusberichten
  • module.use_strict: ingesteld op true als u een transponder gebruikt die "use strict" toevoegt;
  • suppress_comment: een regex die een opmerking definieert om eventuele stroomfouten op de volgende regel te onderdrukken (handig voor lopende code)

Bekijk alle opties in de Flow-gids voor het configureren van opties.

Versie

Flow en het configuratiebestandsformaat evolueren. De [versie] sectie laat je specificeren voor welke versie van Flow het configuratiebestand is ontworpen om verwarrende fouten te voorkomen.

Als de versie van Flow niet overeenkomt met de geconfigureerde versie, geeft Flow een foutmelding weer.

Hier zijn een paar manieren om de ondersteunde versies te specificeren:

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

De caret-versie houdt de eerste niet-nulcomponent van de versie vast. Zo ^ 1.2.3 breidt uit naar het bereik> = 1.2.3 < 2.0.0, and ^ 0.4.5 expandeert naar het bereik> = 0.4.5 < 0.5.0.

Flow gebruiken vanaf de opdrachtregel

Flow is een client-serverprogramma. Er moet een Flow-server worden uitgevoerd en de client maakt verbinding (of start deze als deze niet actief is). De Flow CLI heeft veel opdrachten en opties die handig zijn voor onderhouds- en introspectie doeleinden en voor het tijdelijk negeren van de configuratie van .flowconfig.

Typen stroom --help toont alle commando's en opties. Als u hulp bij een specifieke opdracht wilt, typt u stroom --helpen. Bijvoorbeeld:

$ flow ast --help Gebruik: flow ast [OPTION] ... [FILE] bijv. flow ast foo.js of flow 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) 

Belangrijke opdrachten zijn:

  • in het: genereer een leeg .flowconfig-bestand
  • controleren: voer een volledige stroomcontrole uit en druk de resultaten af 
  • ls: geef bestanden weer die zichtbaar zijn voor Flow
  • staat (standaardinstelling): huidige Flow-fouten van de Flow-server weergeven
  • stel voor: suggesties voor typen voor het doelbestand

Linting met Flow

Flow heeft een pluisstructuur die kan worden geconfigureerd via het .flowconfig-bestand zoals je eerder hebt gezien, via opdrachtregelargumenten of in codebestanden met flowlint-opmerkingen. Alle configuratiemethoden bestaan ​​uit een lijst met sleutel / waarde-paren waarbij de sleutel een regel is en de waarde de ernst is. 

Reglement

Er zijn momenteel drie regels: all, untyped-type-import en sketchy-null. De "All" -regel is in feite de standaardafhandeling voor fouten die geen specifiekere regel hebben. De regel "untyped-type-import" wordt aangeroepen wanneer u een type uit een bestand zonder type importeert. De "sketchy-null" -regel wordt aangeroepen wanneer u een bestaanscontrole uitvoert op een waarde die false of null / undefined kan zijn. Er zijn meer gedetailleerde regels voor:

  • schetsmatig-null-bool
  • schetsmatig-null-nummer
  • schetsmatig-null-string
  • -Schetsmatig nul gemengde

Prioriteitsniveaus

Er zijn ook drie prioriteitsniveaus: uit, waarschuwing en fout. Zoals je je wel kunt voorstellen, "off" slaat de typecontrole over, "warn" produceert waarschuwingen, waardoor de typecontrole niet wordt afgesloten en standaard niet verschijnt in de CLI-uitvoer (je kunt ze zien met --omvatten-waarschuwingen) en "fout" wordt behandeld als flow-fouten en zorgt ervoor dat de typecontrole wordt afgesloten en geeft een foutmelding weer.

Lint met commandoregelargumenten

Gebruik de --lints opdrachtregelargument om meerdere pluisregels op te geven. Bijvoorbeeld:

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

Linting met flowlint Opmerkingen

Er zijn drie soorten opmerkingen: flowlint, flowlint-regel en flowlint-next-line.

De "flowlint" -commentaar past een set regels toe in een blok totdat deze wordt overschreven door een overeenkomende opmerking:

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

Als er geen overeenkomende opmerking is, zijn de instellingen van toepassing tot het einde van het bestand.

De "flowlint-regel" is alleen van toepassing op de huidige regel:  

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

De "flowlint-next-line" is van toepassing op de regel na de opmerking:

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

Conclusie

Grote JavaScript-projecten die door grote teams zijn ontwikkeld, kunnen veel baat hebben bij statische typecontrole. Er zijn verschillende oplossingen voor het introduceren van statische typecontrole in een JavaScript-codebase. 

JavaScript blijft op verschillende manieren groeien op internet. Het is niet zonder zijn leercurven, en er zijn genoeg kaders en bibliotheken om je bezig te houden, zoals je kunt zien. Als u op zoek bent naar extra bronnen om te studeren of te gebruiken in uw werk, kijk dan wat we beschikbaar hebben op de Envato-marktplaats.

Facebook's Flow is een recente en robuuste oplossing met uitstekende dekking, tooling en documentatie. Probeer het eens als je een grote JavaScript-codebase hebt.