Gör din JavaScript-kod robust med flöde

JavaScript var alltid ett viktigt programmeringsspråk, det enda språket som löser sig pålitligt i webbläsaren. De senaste trenderna i front-end-utveckling samt Node.js-baserad back-end-utveckling har drivit skalaen och komplexiteten hos JavaScript-applikationer. 

Stora applikationer som utvecklats av stora lag kan dra nytta av statisk typkontroll, vilket vanilj JavaScript saknar. Flow har utvecklats av Facebook för att lösa problemet. Det är en statisk typkontroll som integreras i din utvecklingsprocess, fångar mycket problem tidigt och hjälper dig att flytta snabbt.

Vad är flöde?

Flow är ett verktyg som kontrollerar din annoterade JavaScript-kod och upptäcker olika problem som utan att det skulle upptäckas endast vid körning (eller sämre, inte upptäckt och korrumperade dina data). Här är ett snabbt exempel.

// @flow funktion getGreeting (namn: sträng): sträng return "Hej, $ name ';  const http = kräver ("http"); const greeting = getGreeting ("Gigi") const port = 8888 console.log ("Lyssnar på port $ port ...") http.createServer (funktion (begäran, svar) response.writeHead (200, "Content-Type ":" text / plain "); response.write (hälsning); response.end ();). lyssna (port);

Flöde mot TypeScript

Innan du dyker in i de snygga detaljerna i Flow, är det värt att jämföra det med andra alternativ, och i synnerhet TypeScript. TypeScript är en strikt uppsättning av JavaScript som utvecklats av Microsoft. Alla JavaScript-program är också ett TypeScript-program. 

TypeScript lägger till valfria typannonser och övergripande tjänar samma syfte som Flow. Det finns emellertid några viktiga skillnader. TypeScript är ett separat programmeringsspråk som kompilerar till JavaScript, medan flödesannoteringar måste tas bort för att komma tillbaka till giltigt JavaScript. 

TypeScript har bra verktyg och IDE-stöd. Flödet hamnar (till exempel JetBrains WebStorm har inbyggd Flow integration).

Den viktigaste filosofiska skillnaden är att Flow lägger tonvikt på sundhet. TypeScript 1.0 fångade inte nollfel; TypeScript 2.0 med stränga null kontroller uppmätta till Flow i detta avseende. Men i andra aspekter som generiska behållare eller maskinskrivning är TypeScript mer permissiv och tillåter olika kategorier av fel genom (endast strukturell typning kontrolleras, inte nominell typning).

TypeScript som sitt eget språk lägger till koncept och språkfunktioner som klasser, gränssnitt, synlighetsindikatorer (offentliga, privata, läsande) och dekoratörer. Dessa funktioner gör det lättare att förstå och använda för personer som kommer från vanliga objektorienterade språk som C ++, Java och C #.

Installation

Eftersom flödesannonser inte är standard JavaScript måste de tas bort innan du sätter i din ansökan. Så här installerar du flöde och flödesavlägsnande typer via garn: garn add -dev flödesfack flyt-bort-typer

Du kan lägga till ett par skript till din package.json-fil för att automatisera processen:

 "skript": "build": "flöde-ta bort-typer src / -d lib /", "prepublish": "garn kör bygg" 

Du bör köra prepublish-skriptet innan du publicerar din kod till registret npm.

För andra installationsalternativ (t ex med hjälp av npm eller babel), kolla in installationsguiden för flöde.

För att avsluta installationen, skriv: garnströmsflöde init

Detta skapar den önskade .flowconfig-filen.

Typ System

Flödet har två viktiga mål: precision och hastighet. Dess typsystem utformades för att stödja dessa mål.

Precision

Precision uppnås genom att analysera hur koden interagerar med typer, antingen annoterade eller avledda. Eventuell felaktighet ger upphov till ett typfel. Annoterade typer stödjer nominell typning, vilket innebär att två olika typer med samma attribut skiljer sig från varandra och kan inte ersättas. Typen av en variabel definieras som uppsättningen runtime-värden som variabeln kan ta emot. 

Fart

Flödet är snabbt på grund av en kombination av modularitet och distribuerad bearbetning. Filerna analyseras parallellt, och resultaten slås samman senare via effektivt delat minne för att utföra fullständig programtypkontroll.

Stödda typer

Flödet stöder många typer. Förutom primitiva typer stöder den också följande:

  • Objekt
  • Array
  • Några
  • Kanske
  • Variabel
  • tupel
  • Klass
  • Gränssnitt
  • Generisk

Skriv anteckningar

Flow kan du deklarera typer samt begränsa variabler och parametrar till valda värden:

skriv Two2Four = 2 | 3 | 4 funktion dubbelIt (antal: Two2Four) returnummer * 2 console.log (doubleIt (3)) Utgång: 6 

Om du överskrider det giltiga intervallet får du ett fel:

console.log (doubleIt (3)) Utgång: Fel: src / main.js: 30 30: console.log (doubleIt (5)) // error ^ nummer. Denna typ är inkompatibel med den förväntade param-typen av 24: funktion doubleIt (number: Two2Four) ^^^^^^^^ number enum Hittade 1 fel 

Du kan också definiera komplexa typer, inklusive subtyping. I följande kodexempel är krigstypen en undertyp av Person. Det betyder att det är OK att returnera en krigare som person från bekämpa() fungera. Återvändande null är dock förbjudet.

typ Person = namn: sträng, ålder: nummer typ Warrior = namn: sträng, ålder: antal, styrka: nummer låt redWolf: Warrior = namn: "Red Wolf", ålder: 24, styrka: 10 låt Skull Crusher: Warrior = name: "Skull Crusher", ålder: 27, styrka: 11 funktionskamp (w1: Warrior, w2: Warrior): Person if (w1.strength> w2.strength) return w1 w2.strength> w1.strength) return w2 returnera null Utgång: Hittade 1 fel $ flöde Fel: src / main.js: 47 47: return null ^^^^ null. Denna typ är inkompatibel med förväntad returtyp av 39: funktionskamp (w1: Warrior, w2: Warrior): Person ^^^^^^ objekttyp Hittade 1 fel 

För att fixa det, låt oss återvända till den yngre krigare om båda krigarna har samma styrka:

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

Flöde tillåter ännu mer exakt kontroll via klassförlängning, invarians, samvariation och kontraavvikelse. Kolla in flödesdokumentationen om varians.

Konfiguration

Flow använder konfigurationsfilen .flowconfig i projektets rotkatalog. Den här filen innehåller flera avsnitt som låter dig konfigurera vilka filer Flow ska kontrollera och de många aspekterna av dess funktion. 

Inkludera

De [inkludera] avsnittet styr vilka kataloger och filer som ska kontrolleras. Rotkatalogen är alltid inkluderad som standard. Stegen i [inkludera] sektionerna är relativa. En enda stjärna är ett vildkort för alla filnamn, tillägg eller katalognamn. Två stjärnor är ett vildkort för valfri katalogdjup. Här är ett prov [inkludera] sektion:

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

Ignorera

De [ignorera] avsnittet är komplementet till [inkludera]. Filer och kataloger du anger här kommer inte att kontrolleras med flöde. Otroligt, det använder en annan syntax (OCaml regelbundna uttryck) och kräver absoluta vägar. Ändra detta är på färdplanen för flödeslaget.

Innan dess, kom ihåg att avsnittet inkluderas behandlas först, följt av ignoreringsdelen. Om du inkluderar och ignorerar samma katalog och / eller fil ignoreras den. För att lösa det absoluta sökproblemet är det vanligt att prefixa varje rad med .*. Om du vill ignorera kataloger eller filer under roten kan du använda  platshållare istället för .*. Här är ett prov [ignorera] sektion:

[ignorera]. * / __ tester __ /. *. * / src / \ (foo \ | bar \) /.*. * \. ignorera \ .js /ignore_me.js

libs

Alla icke-triviala JavaScript-applikationer använder många bibliotek från tredje part. Flöde kan kontrollera hur din applikation använder dessa bibliotek om du tillhandahåller speciella libdef-filer som innehåller typinformation om dessa bibliotek. 

Flow skannar automatiskt "flödesskrivet" underkatalog för ditt projekt för libdef-filer, men du kan också ge sökvägen till libdef-filer i avsnittet [libs]. Detta är användbart om du behåller ett centralt arkiv av libdef-filer som används av flera projekt.

Importera befintliga typdefinitioner och skapa egna om målbiblioteket inte tillhandahåller egna typdefinitioner är ganska enkelt. Se:

  • Flödedokumentation: Bibliotek Definitioner
  • Flödedokumentation: Skapa biblioteksdefinitioner
  • GitHub: Importera och använda bibliotekets definitioner

Lints

Flödet har flera lintregler du kan styra och bestämma hur man behandlar dem. Du kan konfigurera reglerna från kommandoraden, i kodkommentarer eller i [lints] delen av din config-fil. Jag ska diskutera linting i nästa avsnitt, men här är hur du konfigurerar den med hjälp av [lints] sektion:

[lints] all = varna untyped-type-import = fel sketchy-null-bool = av

alternativ

De [alternativ] avsnittet är där du får berätta för Flow hur man beter sig i en mängd olika fall som inte förtjänar sin egen sektion, så de är alla grupperade ihop.

Det finns för många alternativ att lista dem alla här. Några av de mer intressanta är:

  • Allt: Ange till sant för att kontrollera alla filer, inte bara de med @flow
  • emoji: Ange till true för att lägga till emojis till statusmeddelanden
  • module.use_strict: Ange till true om du använder en transpiler som lägger till "använd strikt"
  • suppress_comment: en regex som definierar en kommentar för att undertrycka flödesfel på följande rad (användbar för in-progress-kod)

Kolla in alla alternativ i flödesguiden för att konfigurera alternativ.

Version

Flöde och dess konfigurationsfilformat utvecklas. De [version] avsnittet kan du ange vilken version av flödet konfigurationsfilen är utformad för att undvika förvirrande fel.

Om versionen av Flow inte stämmer överens med den konfigurerade versionen visar Flow ett felmeddelande.

Här är några sätt att ange vilka versioner som stöds:

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

Caret-versionen håller fast den första icke-nollkomponenten i versionen. Så ^ 1.2.3 expanderar till intervallet> = 1.2.3 < 2.0.0, and ^ 0.4.5 expanderar till intervallet> = 0,4 < 0.5.0.

Använda flöde från kommandoraden

Flow är ett klient-serverprogram. En flödesserver måste köras och klienten ansluter till den (eller startar den om den inte körs). Flow CLI har många kommandon och alternativ som är användbara för underhålls- och introspektionsändamål samt för att tillfälligt överväga konfiguration från .flowconfig.

Skriver flöde - hjälp visar alla kommandon och alternativ. För att få hjälp med ett visst kommando, skriv strömma --hjälp. Till exempel:

$ flow ast --help Användning: flöde ast [OPTION] ... [FILE] t.ex. flöde ast foo.js eller flöde 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) 

Viktiga kommandon är:

  • i det: skapa en tom .flowconfig-fil
  • kontrollera: gör en fullständig flödeskontroll och skriv ut resultaten 
  • ls: visa filer som är synliga för flöde
  • status (standard): visa aktuella flödesfel från flödesservern
  • föreslå: föreslå typer för målfilen

Linting With Flow

Flödet har ett lintingramverk som kan konfigureras via .flowconfig-filen som du såg tidigare, genom kommandoradsargument eller i kodfiler med flödeslinskommentarer. Alla konfigurationsmetoder består av en lista över nyckelvärdespar där nyckeln är en regel och värdet är svårighetsgraden. 

regler

Det finns för närvarande tre regler: allt, otypad typ-import och sketchy-null. "All" -regeln är verkligen standardhanteringen för eventuella fel som inte har en mer specifik regel. Regeln "Untyped-Type-Import" åberopas när du importerar en typ från en otypad fil. Regeln "sketchy-null" åberopas när du gör existensen, kontrollera ett värde som kan vara falskt eller null / odefinierat. Det finns mer granulära regler för:

  • skissartade-null-bool
  • skissartade-null-antal
  • skissartade-null-sträng
  • skissartade-null-blandade

Severitetsnivåer

Det finns också tre svårighetsgrader: av, varning och fel. Som du kan tänka dig, "off" hoppar över typkontrollen, "varnar" producerar varningar, vilket inte medför att typkontrollen avslutas och inte visas som standard i CLI-utgången (du kan se dem med --inkluderar-varningar), och "fel" hanteras precis som flödesfel och orsakar typkontrollen för att avsluta och visa ett felmeddelande.

Linting med kommandoradsargument

Använd --lints kommandoradsargument för att ange flera lintregler. Till exempel:

flöde - linjer "all = varna, untyped-type-import = fel, sketchy-null-bool = off"

Linting With flowlint Kommentarer

Det finns tre typer av kommentarer: flowlint, flowlint-line och flowlint-next-line.

"Flowlint" -kommentaren tillämpar en uppsättning regler i ett block tills det överrätts av en matchande kommentar:

importtyp // flowlint untyped-type-import: av Foo, Bar, Baz, // flowlint untyped-type-import: error från './untyped.js'; 

Om det inte finns någon matchande kommentar gäller inställningarna helt enkelt till slutet av filen.

"Flowlint-line" gäller bara den nuvarande raden:  

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

"Flowlint-next-line" gäller för raden som följer kommentaren:

funktion (x:? boolean) // flowlint-next-line sketchy-null-bool: av om (x) ... annars ... 

Slutsats

Stora JavaScript-projekt som utvecklats av stora lag kan gynna mycket av statisk typkontroll. Det finns flera lösningar för att införa statisk typkontroll i en JavaScript-kodbas. 

JavaScript fortsätter att växa på olika sätt över hela webben. Det är inte utan sina inlärningskurvor, och det finns gott om ramar och bibliotek för att hålla dig upptagen, som du kan se. Om du letar efter ytterligare resurser att studera eller använda i ditt arbete, kolla vad vi har tillgängligt på Envato-marknaden.

Facebook Flow är en ny och robust lösning med utmärkt täckning, verktyg och dokumentation. Ge det ett försök om du har en stor JavaScript-kodbas.