Rendi il tuo codice JavaScript robusto con il flusso

JavaScript è sempre stato un linguaggio di programmazione significativo, essendo l'unico linguaggio che funziona in modo affidabile nel browser. Le recenti tendenze nello sviluppo front-end e lo sviluppo back-end basato su Node.js hanno spinto la scala e la complessità delle applicazioni JavaScript. 

Le applicazioni di grandi dimensioni sviluppate da grandi team possono trarre vantaggio dal controllo di tipo statico, che manca a JavaScript di vanilla. Flow è stato sviluppato da Facebook per risolvere questo problema. È un controllo di tipo statico che si integra nel tuo processo di sviluppo, affronta molti problemi in anticipo e ti aiuta a muoverti velocemente.

Che cos'è il flusso?

Flow è uno strumento che controlla il codice JavaScript annotato e rileva vari problemi che senza di esso verrebbero rilevati solo a runtime (o peggio, non scoperto e corrotto i tuoi dati). Ecco un rapido esempio.

// @flow function getGreeting (name: string): string return 'Ciao, $ nome';  const http = require ("http"); const greeting = getGreeting ("Gigi") const port = 8888 console.log ('Ascolto su porta $ porta ...') http.createServer (funzione (richiesta, risposta) response.writeHead (200, "Content-Type ":" text / plain "); response.write (greeting); response.end ();). listen (port);

Flow vs. TypeScript

Prima di immergerti nei dettagli nitidi di Flow, vale la pena confrontarlo con altre alternative, in particolare con TypeScript. TypeScript è un superset di JavaScript sviluppato da Microsoft. Qualsiasi programma JavaScript è anche un programma TypeScript. 

TypeScript aggiunge annotazioni di tipo opzionali e nel complesso ha lo stesso scopo di Flow. Tuttavia, ci sono alcune importanti differenze. TypeScript è un linguaggio di programmazione separato che viene compilato in JavaScript, mentre le annotazioni Flow devono essere rimosse per tornare a JavaScript valido. 

TypeScript ha un ottimo strumento e supporto IDE. Il flusso sta recuperando (ad esempio, JetBrains WebStorm ha un'integrazione nativa del flusso).

La differenza filosofica più importante è che Flow pone l'accento sulla solidità. TypeScript 1.0 non ha rilevato errori nulli; TypeScript 2.0 con rigorosi controlli null misurati fino a Flow in questo senso. Ma in altri aspetti come i contenitori generici o la digitazione, TypeScript è più permissivo e consente varie categorie di errori (viene controllata solo la tipizzazione strutturale, non battitura nominale).

TypeScript come lingua propria aggiunge concetti e caratteristiche linguistiche come classi, interfacce, indicatori di visibilità (pubblici, privati, readonly) e decoratori. Queste funzionalità rendono più facile la comprensione e l'utilizzo per le persone che provengono da linguaggi orientati agli oggetti tradizionali come C ++, Java e C #.

Installazione

Poiché le annotazioni Flow non sono JavaScript standard, devono essere rimosse prima di distribuire l'applicazione. Ecco come installare il flusso e rimuovere i tipi di flusso tramite filato: filato aggiunto --dev flow-remove flow-remove-types

È possibile aggiungere un paio di script al file package.json per automatizzare il processo:

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

È necessario eseguire lo script di preparazione prima di pubblicare il codice nel registro di npm.

Per altre opzioni di installazione (ad esempio utilizzando npm o babel), consultare la guida all'installazione di Flow.

Per completare l'installazione, digitare: inizio del flusso di filato

Questo creerà il file .flowconfig richiesto.

Digitare Sistema

Il flusso ha due obiettivi importanti: precisione e velocità. Il suo sistema tipo è stato progettato per supportare questi obiettivi.

Precisione

La precisione si ottiene analizzando il modo in cui il codice interagisce con i tipi, annotati o dedotti. Qualsiasi disallineamento genera un errore di tipo. I tipi annotati supportano la digitazione nominale, il che significa che due tipi diversi con gli stessi attributi si distinguono l'uno dall'altro e non possono essere sostituiti. Il tipo di una variabile è definito come l'insieme di valori di runtime che la variabile può ricevere. 

Velocità

Il flusso è veloce grazie a una combinazione di modularità e elaborazione distribuita. I file vengono analizzati in parallelo e i risultati vengono uniti in seguito tramite un'efficiente memoria condivisa per eseguire il controllo del tipo di programma completo.

Tipi supportati

Flow supporta molti tipi. Oltre ai tipi primitivi, supporta anche quanto segue:

  • Oggetto
  • schieramento
  • Qualunque
  • Può essere
  • Variabile
  • tuple
  • Classe
  • Interfaccia
  • Generico

Digita annotazioni

Flow consente di dichiarare i tipi e di limitare variabili e parametri ai valori selezionati:

digitare Two2Four = 2 | 3 | 4 funzione doubleIt (numero: Two2Four) numero di ritorno * 2 console.log (doubleIt (3)) Output: 6 

Se superi l'intervallo valido, riceverai un errore:

console.log (doubleIt (3)) Output: Errore: src / main.js: 30 30: console.log (doubleIt (5)) // errore ^ numero. Questo tipo non è compatibile con il tipo di parametro previsto di 24: function doubleIt (numero: Two2Four) ^^^^^^^^ numero enum Trovato 1 errore 

È inoltre possibile definire tipi complessi, inclusa la sottotipizzazione. Nell'esempio di codice seguente, il tipo Warrior è un sottotipo di Person. Ciò significa che è OK restituire un Guerriero come Persona dal combattimento() funzione. Tuttavia, restituire null è vietato.

digita Person = nome: stringa, età: numero tipo Guerriero = nome: stringa, età: numero, forza: numero lascia redWolf: Guerriero = nome: "Lupo rosso", età: 24, punto di forza: 10 lascia skullCrusher: Warrior = name: "Skull Crusher", età: 27, forza: 11 function fight (w1: Warrior, w2: Warrior): Person if (w1.strength> w2.strength) return w1 if ( w2.strength> w1.strength) return w2 return null Output: Trovato 1 errore $ flow Errore: src / main.js: 47 47: return null ^^^^ null. Questo tipo non è compatibile con il tipo di ritorno previsto di 39: function fight (w1: Warrior, w2: Warrior): Person ^^^^^^ tipo di oggetto Trovato 1 errore 

Per risolverlo, restituiamo il guerriero più giovane se entrambi i guerrieri hanno la stessa forza:

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 

Il flusso consente un controllo ancora più preciso tramite estensione di classe, invarianza, co-varianza e contro-varianza. Controlla la documentazione Flow sulla varianza.

Configurazione

Flow usa il file di configurazione .flowconfig nella directory principale dei tuoi progetti. Questo file contiene diverse sezioni che ti permettono di configurare quali file dovrebbero controllare il flusso e i molti aspetti del suo funzionamento. 

Includere

Il [includere] sezione controlla quali directory e file devono essere controllati. La directory root è sempre inclusa per impostazione predefinita. I percorsi nel [includere] le sezioni sono relative. Una singola stella è una wild-card per qualsiasi nome di file, estensione o nome della directory. Due stelle sono una wild card per qualsiasi profondità di directory. Ecco un esempio [includere] sezione:

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

Ignorare

Il [ignorare] la sezione è il complemento di [includere]. I file e le directory che specifichi qui non saranno controllati dal flusso. Stranamente, usa una sintassi diversa (espressioni regolari OCaml) e richiede percorsi assoluti. Cambiando questo è sulla tabella di marcia del team di flusso.

Fino ad allora, ricorda che la sezione include viene elaborata per prima, seguita dalla sezione ignora. Se includi e ignori la stessa directory e / o file, verrà ignorata. Per risolvere il problema del percorso assoluto, è normale anteporre ogni riga a .*. Se si desidera ignorare directory o file sotto la radice, è possibile utilizzare  segnaposto invece di .*. Ecco un esempio [ignorare] sezione:

[ignore]. * / __ test __ /. *. * / src / \ (foo \ | bar \) /.*. * \. ignore \ .js /ignore_me.js

libs

Qualsiasi applicazione JavaScript non banale utilizza molte librerie di terze parti. Flow può verificare in che modo l'applicazione utilizza queste librerie se si forniscono file libdef speciali che contengono informazioni di tipo su queste librerie. 

Flow analizza automaticamente la sottodirectory "flow-typed" del tuo progetto per i file libdef, ma puoi anche fornire il percorso dei file libdef nella sezione [libs]. Ciò è utile se si mantiene un repository centrale di file libdef utilizzati da più progetti.

Importare definizioni di tipi esistenti e crearne di proprie se la libreria di destinazione non fornisce le proprie definizioni di tipo è piuttosto semplice. Vedere:

  • Documentazione del flusso: definizioni della libreria
  • Documentazione del flusso: creazione di definizioni di libreria
  • GitHub: importazione e utilizzo delle definizioni della libreria

lints

Flow ha diverse regole di filaccia che è possibile controllare e determinare come trattarle. È possibile configurare le regole dalla riga di comando, nei commenti del codice o nel file [garze] sezione del tuo file di configurazione. Discuterò di linting nella prossima sezione, ma qui è come configurarlo usando il [garze] sezione:

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

Opzioni

Il [opzioni] sezione è dove devi dire a Flow come comportarsi in una varietà di casi che non meritano la propria sezione, quindi sono tutti raggruppati insieme.

Ci sono troppe opzioni per elencarle tutte qui. Alcuni dei più interessanti sono:

  • tutti: impostato su true per controllare tutti i file, non solo quelli con @flow
  • emoji: impostato su true per aggiungere emoji ai messaggi di stato
  • module.use_strict: impostato su true se si utilizza un transpiler che aggiunge "use strict;"
  • suppress_comment: un'espressione regolare che definisce un commento per sopprimere eventuali errori di flusso nella riga seguente (utile per codice in corso)

Scopri tutte le opzioni nella guida di flusso per configurare le opzioni.

Versione

Flow e il suo formato di file di configurazione si evolvono. Il [versione] sezione consente di specificare quale versione di Flow è progettata per il file di configurazione per evitare errori confusi.

Se la versione di Flow non corrisponde alla versione configurata, Flow visualizzerà un messaggio di errore.

Ecco alcuni modi per specificare le versioni supportate:

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

La versione caret mantiene fisso il primo componente diverso da zero della versione. Così ^ 1.2.3 si espande nell'intervallo> = 1.2.3 < 2.0.0, and ^ 0.4.5 si espande nell'intervallo> = 0.4.5 < 0.5.0.

Utilizzo del flusso dalla riga di comando

Flow è un programma client-server. Un server Flow deve essere in esecuzione e il client si connette ad esso (o lo avvia se non è in esecuzione). La CLI di flusso ha molti comandi e opzioni utili per gli scopi di manutenzione e introspezione e per la configurazione temporanea di overflow di .flowconfig.

Digitando flusso - aiuto mostra tutti i comandi e le opzioni. Per ottenere aiuto su un comando specifico, digitare flusso --Aiuto. Per esempio:

$ flow ast --help Utilizzo: flow ast [OPTION] ... [FILE] ad es. flusso ast foo.js o flusso 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) 

I comandi importanti sono:

  • dentro: genera un file .flowconfig vuoto
  • dai un'occhiata: eseguire un controllo di flusso completo e stampare i risultati 
  • ls: visualizza i file visibili a Flow
  • stato (predefinito): mostra gli errori di flusso correnti dal server Flow
  • suggerire: suggerire tipi per il file di destinazione

Linting With Flow

Flow ha un framework di linting che può essere configurato tramite il file .flowconfig come si è visto in precedenza, tramite gli argomenti della riga di comando o nei file di codice che usano i commenti di flowlint. Tutti i metodi di configurazione consistono in un elenco di coppie chiave-valore in cui la chiave è una regola e il valore è la gravità. 

Regole

Esistono attualmente tre regole: tutte, non tipizzate, di tipo import e null abbozzate. La regola "Tutti" è in realtà la gestione predefinita per gli errori che non hanno una regola più specifica. La regola "importazione tipo non tipizzata" viene invocata quando si importa un tipo da un file non tipizzato. La regola "abbozzato-null" viene invocata quando si verifica l'esistenza su un valore che può essere falso o nullo / non definito. Esistono regole più granulari per:

  • abbozzato-nullo-bool
  • abbozzato-nullo-number
  • abbozzato-nullo-stringa
  • abbozzato-nullo-miscelati

Livelli di gravità

Esistono anche tre livelli di gravità: disattivato, avviso ed errore. Come puoi immaginare, "off" salta il controllo del tipo, "warn" produce avvertimenti, che non fanno uscire il controllo del tipo e non si visualizzano per impostazione predefinita nell'output CLI (puoi vederli con --includere-warnings), e "errore" viene gestito come gli errori di flusso e causa l'uscita del controllo del tipo e la visualizzazione di un messaggio di errore.

Linting con argomenti della riga di comando

Utilizzare il --garze argomento della riga di comando per specificare più regole lint. Per esempio:

flusso --lints "all = warn, untyped-type-import = errore, sketchy-null-bool = off"

Linting With flowlint Commenti

Esistono tre tipi di commenti: flowlint, flowlint-line e flowlint-next-line.

Il commento "flowlint" applica un insieme di regole in un blocco fino a quando non viene sovrascritto da un commento corrispondente:

tipo di importazione // flowlint untyped-type-import: off Foo, Bar, Baz, // flowlint untyped-type-import: errore da './untyped.js'; 

Se non ci sono commenti corrispondenti, le impostazioni si applicano semplicemente fino alla fine del file.

La "linea di flusso" si applica solo alla linea corrente:  

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

Il "flowlint-next-line" si applica alla riga che segue il commento:

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

Conclusione

I grandi progetti JavaScript sviluppati da grandi team possono trarre grandi vantaggi dal controllo di tipo statico. Esistono diverse soluzioni per l'introduzione del controllo di tipo statico in una base di codice JavaScript. 

JavaScript continua a crescere in una varietà di modi attraverso il web. Non è senza le sue curve di apprendimento, e ci sono un sacco di quadri e librerie per tenerti occupato, come puoi vedere. Se stai cercando ulteriori risorse da studiare o da utilizzare nel tuo lavoro, dai un'occhiata a ciò che abbiamo a disposizione sul mercato Envato.

Il flusso di Facebook è una soluzione recente e solida con copertura, strumenti e documentazione eccellenti. Fai un tentativo se hai una grande base di codice JavaScript.