Implementazione di interfacce in JavaScript con Implement.js

Josh J
Josh J

Seguire

Nov 7, 2017 · 5 min di lettura

In questo post del blog vorrei introdurre il concetto di interfacce e come possono essere utili anche in linguaggi dinamici. Userò anche l’implementazione della libreria.js per portare il concetto in JavaScript e mostrarti come ottenere qualche utilità extra dalle interfacce.

Google definisce un’interfaccia come “un punto in cui due sistemi, soggetti, organizzazioni, ecc. meet and interact”, e questa definizione vale per le interfacce nella programmazione. Nello sviluppo del software, un’interfaccia è una struttura che applica proprietà specifiche su un oggetto – nella maggior parte delle lingue questo oggetto è una classe.

Ecco un esempio di un’interfaccia in Java:

Nell’esempio precedente, l’interfacciaCar descrive una classe che ha due metodi senza tipo di ritorno, entrambi i quali prendono un singolo argomento intero. I dettagli dell’implementazione di ogni funzione sono lasciati alla classe, questo è il motivo per cui i metodi non hanno corpo. Per garantire che una classe implementi l’interfacciaCar, usiamo la parola chiaveimplements :

Semplice

Interfacce in JavaScript

Le interfacce non sono una cosa in JavaScript, non in realtà comunque. JavaScript è un linguaggio dinamico, uno in cui i tipi vengono cambiati così spesso che lo sviluppatore potrebbe non essersi nemmeno reso conto, a causa di ciò le persone sostengono che non è necessario aggiungere un’interfaccia allo standard ECMAScript su cui si basa JavaScript.

Tuttavia, JavaScript è cresciuto in modo massiccio come linguaggio di backend sotto forma di Nodo.js, e con ciò arrivano requisiti diversi e una folla diversa che potrebbe avere un’opinione diversa. Per aggiungere a questo, il linguaggio sta rapidamente diventando lo strumento front-end; è arrivato al punto in cui molti sviluppatori scriveranno la stragrande maggioranza del loro HTML all’interno .file js sotto forma di JSX.

Così come la lingua cresce ad assumere più ruoli, è utile quindi per assicurarsi che una delle nostre strutture di dati più cruciali è quello che ci aspettavamo che fosse. JavaScript può avere la parola chiave class, ma in realtà questa è solo una funzione di costruttore disinstallata, e una volta chiamata è semplicemente un oggetto. Gli oggetti sono onnipresenti, quindi a volte è utile assicurarsi che corrispondano a una forma specifica.

Recentemente al lavoro ho trovato un caso in cui uno sviluppatore si aspettava che una proprietà restituita come parte di una risposta API fossetrue ma invece ha ottenuto"true", causando un bug. Un errore facile, e uno che avrebbe potuto anche essere evitato se avessimo avuto un’interfaccia.

Ma aspetta, c’è di più!

Le interfacce, con alcune modifiche minori, potrebbero essere utilizzate per rimodellare gli oggetti. Immagina di implementare un’interfaccia “rigorosa”, in cui non sono consentite proprietà al di fuori dell’interfaccia, potremmo eliminare o rinominare queste proprietà o persino generare un errore se le incontriamo.

Quindi ora abbiamo un’interfaccia che ci dirà quando mancano determinate proprietà, ma anche quando abbiamo proprietà inaspettate, o se i tipi delle proprietà non sono quelli che ci aspettiamo. Ciò aggiunge altre possibilità, ad esempio il refactoring di una risposta da un’API aggiungendo quel ulteriore livello di sicurezza in cima al comportamento standard dell’interfaccia. Potremmo anche usare le interfacce nei test unitari se abbiamo errori di lancio.

Implementare.js

Implementare.js è una libreria che tenta di portare interfacce in JavaScript. L’idea è semplice: definire un’interfaccia, definire i tipi delle sue proprietà e usarla per garantire che un oggetto sia quello che ci si aspetta che sia.

Setup

Prima installa il pacchetto:

npm install implement-js

Quindi, crea un .js file e importare implementInterface e type:

la Nostra prima interfaccia

Per creare un’interfaccia, semplicemente chiamata Interface e passare una stringa come il nome della vostra interfaccia — non è raccomandato, ma se si omette il nome di un ID univoco che verrà generato. Questo restituisce una funzione che accetta un oggetto in cui le proprietà sono tutte type oggetti, un secondo argomento può anche essere passato con opzioni per visualizzare gli avvisi, gettare errori, eliminare o rinominare proprietà, garantire che solo le proprietà dell’interfaccia sono presenti, o per estendere esistente Interface.

Ecco un’interfaccia che descrive un’auto:

è un seats proprietà che deve essere di tipo numero di passeggeri array che contiene gli oggetti che devono implementare il Passenger interfaccia, e contiene un beep proprietà, che dovrebbe essere una funzione. Le opzionierror estrict sono state impostate su true, il che significa che gli errori verranno generati quando manca una proprietà dell’interfaccia e anche quando viene trovata una proprietà non sull’interfaccia.

Implementazione della nostra interfaccia

Ora vogliamo implementare la nostra interfaccia, in un semplice esempio creeremo un oggetto usando un oggetto letterale e vedremo se siamo in grado di implementare la nostra interfaccia.

Per prima cosa, creiamo un oggettoFord, quindi tenteremo di implementarlo contro il nostroCar interfaccia:

Come vediamo da il commento sopra, questo genera un errore. Diamo un’occhiata al nostroCar interfaccia:

Possiamo vedere che mentre tutte le proprietà sono presenti, anche la modalità rigorosa è vera, il che significa che la proprietà aggiuntivafuelType causa un errore da generare. Inoltre, sebbene abbiamo una proprietàpassengers, non è un array.

Per implementare correttamente l’interfaccia, rimuoviamo fuelType e cambiamo il valore di passengers in modo che sia un array contenente oggetti che implementano l’interfaccia Passenger :

“Ma JavaScript non è un linguaggio orientato agli oggetti!”

È vero che mentre le interfacce sono tipicamente associate a linguaggi orientati agli oggetti e JavaScript è un linguaggio multi-paradigma che utilizza l’ereditarietà prototipale, le interfacce possono ancora essere molto utili.

Ad esempio, utilizzando implement-js possiamo facilmente refactoring una risposta API, garantendo nel contempo che non ha deviato da quello che ci aspettiamo. Ecco un esempio utilizzato in combinazione con redux-thunk:

in Primo luogo, definiamo il TwitterUser interfaccia, che estende il User l’interfaccia di un oggetto con twitterId e twitterUsername proprietà. trimè vero, il che significa che scarteremo tutte le proprietà non descritte nell’interfacciaTwitterUser. Poiché la nostra API restituisce le proprietà in un formato ostile, abbiamo rinominato le proprietà da twitter_username e twitter_id alle versioni camelcase di se stessi.

Successivamente, definiamo un’azione asincrona conredux-thunk, l’azione attiva una chiamata API e usiamo la nostra interfacciaTwitterUser per scartare le proprietà che non vogliamo e per assicurarci che implementi le proprietà che ci aspettiamo, con i tipi corretti. Se preferisci mantenere i tuoi creatori di azioni puri (er) o non usare redux-thunk, potresti voler controllare l’interfaccia all’interno di twitterService.getUser e restituire il risultato.

Nota: quando si estende un’interfaccia le opzioni non vengono ereditate

I test unitari sono anche un luogo adatto per utilizzare le interfacce:

In sintesi

Abbiamo visto come le interfacce può essere utile in JavaScript: anche se è un ambiente altamente dinamico lingua, controllare la forma di un oggetto e le sue proprietà sono un tipo di dati specifico ci dà un ulteriore livello di sicurezza che altrimenti sarebbe inaccessibile. Basandosi sul concetto di interfacce e utilizzando implement-js siamo anche stati in grado di ottenere un’utilità aggiuntiva oltre alla maggiore sicurezza.

Posted on

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.