Un'introduzione delicata ai decoratori di TypeScript

Demistifica questo potente modello costruendo i decoratori da zero

Foto di Cederic X su Unsplash

I decoratori sono una delle funzionalità più potenti che Typescript ha da offrire, permettendoci di estendere la funzionalità di classi e metodi in modo pulito e dichiarativo. I decoratori sono attualmente una proposta di fase 2 per JavaScript, ma hanno già guadagnato popolarità nell'ecosistema TypeScript, utilizzato da importanti progetti open source come Angular e Inversify.

Per quanto possano essere fantastici decoratori, capire il modo in cui agiscono potrebbe essere sbalorditivo. In questo articolo, ho l'obiettivo di darti una solida comprensione dei decoratori in meno di 5 minuti del tuo tempo. Allora, cosa sono comunque questi decoratori?

I decoratori sono solo una sintassi pulita per racchiudere un pezzo di codice con una funzione

I decoratori sono una caratteristica sperimentale, quindi i dettagli di implementazione potrebbero cambiare in futuro, ma i principi di base sono eterni. Per consentire l'uso dei decoratori aggiungi "sperimentaleDecoratori": vero per le opzioni del tuo compilatore nel file tsconfig.json, e assicurati che il tuo obiettivo di transpilation sia ES5 o successivo.

Ok, il tempo stringe, quindi cominciamo a scrivere codice!

Il viaggio inizia con i decoratori di classe

Supponi di avere un'azienda che affitta vecchi castelli a famiglie potenti e stai lavorando alla creazione di un server HTTP. Hai deciso di costruire ogni endpoint della tua API come classe e i metodi pubblici della classe corrispondevano ai metodi HTTP. Questo potrebbe assomigliare a questo:

È un buon inizio e ora abbiamo bisogno di un modo semplice per "registrare" ciascuna di queste classi come endpoint nel nostro server HTTP. Creiamo una semplice funzione per occuparmene. La nostra funzione otterrà una classe come argomento e aggiungerà un'istanza di quella classe come endpoint al nostro server. Così:

Senza che te ne accorga, abbiamo già scritto il nostro primo decoratore! Esatto, è così semplice. Tutto ciò che un decoratore è, è una funzione che prende una classe come argomento, e qui l'abbiamo. Ora invece di chiamare registerEndpoint in modo "normale", possiamo semplicemente decorare le nostre classi con @registerEndpoint. non mi credi? Dare un'occhiata:

Abbiamo messo in funzione il nostro primo decoratore e ci sono voluti solo 2 minuti circa. Ora siamo pronti per immergerci più a fondo e liberare la potenza del decoratore del metodo.

Scatena il potere del decoratore del metodo

Diciamo che vogliamo proteggere alcuni dei nostri endpoint in modo che solo gli utenti autenticati possano accedervi. Per fare ciò possiamo creare un nuovo decoratore chiamato proteggere. Per ora, tutto ciò che farà il nostro decoratore è quello di aggiungere il metodo protetto a un array chiamato metodo protetto.

Come puoi vedere, il metodo decorator accetta 3 argomenti:

  1. target - Il prototipo della nostra classe (o il costruttore della classe se il metodo decorato è statico).
  2. propertyKey - Il nome del metodo decorato.
  3. descrittore - Un oggetto che contiene la funzione decorata e alcuni metadati che la riguardano.

Finora leggiamo solo informazioni riguardanti le classi e i metodi che abbiamo decorato, ma il vero divertimento inizia quando iniziamo a cambiare il loro comportamento. Possiamo farlo semplicemente restituendo un valore dal decoratore. Quando un decoratore di metodi restituisce un valore, questo valore verrà utilizzato al posto del descrittore originale (che contiene il metodo originale).

Proviamo creando un decoratore chiamato no, che sostituisce il nostro metodo originale con un metodo che stampa "no" ogni volta che viene chiamato. Per fare ciò sostituirò descrittore.valore, che è dove è memorizzata la funzione originale, con la mia funzione:

A questo punto, abbiamo giocato con le basi dei decoratori di metodi, ma non abbiamo ancora creato nulla di utile. Quello che ho intenzione di fare dopo è riscrivere il decoratore di protezione, ma questa volta invece di registrare solo i nomi dei metodi decorati, bloccherà effettivamente le richieste non autorizzate.

Il prossimo passo sarà un po 'più complicato rispetto agli ultimi, quindi abbi pazienza. Ecco i passi che dovremmo prendere:

  1. Estrarre la funzione originale dal descrittore e memorizzarla altrove per un uso successivo.
  2. Sostituisci descrittore.valore con una nuova funzione che accetta gli stessi argomenti dell'originale.
  3. All'interno della nostra nuova funzione, controlla se la richiesta è autenticata e, in caso contrario, genera un errore.
  4. Infine, anche all'interno della nostra nuova funzione, ora possiamo chiamare la funzione originale con gli argomenti di cui ha bisogno, acquisire il suo valore di ritorno e restituirlo.

Stupefacente! Abbiamo un decoratore di protezione completamente operativo. Ora aggiungere o rimuovere la protezione dai nostri metodi è un gioco da ragazzi.

Nota come nella riga 8 associamo la funzione originale a questa, quindi avrà accesso all'istanza della sua classe. Ad esempio, senza questa riga, il nostro metodo get () non sarebbe in grado di leggere this.houses.

Abbiamo fatto un bel po 'di strada ma ce n'è di più davanti. A questo punto, ti incoraggio a prenderti un momento e assicurarti di capire ogni cosa di ciò che abbiamo fatto finora. Per renderti più semplice, ho messo qui tutto il codice qui sopra nel parco giochi in modo che tu possa eseguirlo, modificarlo e romperlo fino a quando senti di averlo capito completamente.

Ottieni più potenza con le fabbriche di decoratori

Supponiamo che ora desideriamo aggiungere un nuovo endpoint per restituire i membri della famiglia Stark, nel percorso / famiglie / stark / membri. Beh, ovviamente non possiamo creare una classe con quel nome, quindi cosa faremo?

Ciò di cui abbiamo bisogno qui è un modo per passare parametri che determineranno il comportamento della nostra funzione decoratore. Diamo un'altra occhiata al nostro buon vecchio registroEndpoint Decorator:

Per inviare parametri al nostro decoratore, dobbiamo trasformarlo da un normale decoratore in una fabbrica di decoratori. Una fabbrica di decoratori è una funzione che restituisce un decoratore. Per crearne uno, tutto ciò che serve è avvolgere il nostro decoratore originale, in questo modo:

Ora possiamo anche avvolgere il nostro decoratore di protezione, in modo da ottenere il token previsto come parametro:

Conclusione

A questo punto hai una buona conoscenza dei decoratori, come funzionano, così come il potere e l'espressività che ci consentono come programmatori. In questo articolo ho trattato le tecniche più utili e comuni, tuttavia, c'è molto altro da imparare. I decoratori in Typescript possono essere applicati non solo alle classi e ai metodi, ma anche alle proprietà delle classi e agli argomenti dei metodi. Spero che con la tua nuova conoscenza acquisita dei decoratori sarai in grado di prenderlo facilmente dalla documentazione. Come sempre, ho inserito tutto il codice di questo articolo nel parco giochi, quindi vai avanti e gioca!

yay, l'hai fatto!

Se ti è piaciuto questo articolo sentiti libero di applaudire così più persone lo troveranno e lo apprezzeranno, e se desideri vedere più cose che scrivo, sei il benvenuto a seguirmi. Fatemi sapere nei commenti se avete domande.

Inoltre, potresti voler dare un'occhiata ai miei altri articoli TypeScript su generici e potenziamento o sulla progettazione delle classi.