Een zachte inleiding tot TypeScript-decorateurs

Demystify dit krachtige patroon door decorateurs helemaal opnieuw te bouwen

Foto door Cederic X op Unsplash

Decorateurs zijn een van de krachtigste functies die Typescript te bieden heeft, waardoor we de functionaliteit van klassen en methoden op een schone en duidelijke manier kunnen uitbreiden. Decorateurs zijn momenteel een fase 2-voorstel voor JavaScript, maar zijn al populair geworden in het TypeScript-ecosysteem, dat wordt gebruikt door toonaangevende open-sourceprojecten zoals Angular en Inversify.

Hoe geweldig decorateurs ook zijn, het begrijpen van de manier waarop ze handelen kan verbijsterend zijn. In dit artikel wil ik u een goed begrip van decorateurs geven in minder dan 5 minuten van uw tijd. Wat zijn deze decorateurs dan eigenlijk?

Decorateurs zijn slechts een schone syntaxis om een ​​stuk code met een functie in te pakken

Decorateurs zijn een experimentele functie, dus implementatiedetails kunnen in de toekomst veranderen, maar de onderliggende principes zijn eeuwig. Om het gebruik van decorateurs toe te staan, voegt u "experimentalDecorators" toe: trouw aan uw compileropties in het bestand tsconfig.json en zorg ervoor dat uw transpilatiedoel ES5 of hoger is.

Oké, de klok tikt dus laten we coderen!

De reis begint met klasse decorateurs

Stel dat u een bedrijf heeft dat oude kastelen verhuurt aan machtige families en dat u werkt aan het opzetten van een HTTP-server. U hebt besloten om elk eindpunt van uw API als een klasse te bouwen, en de openbare methoden van de klasse zouden overeenkomen met de HTTP-methoden. Dit kan er ongeveer zo uitzien:

Dat is een goed begin, en nu hebben we een eenvoudige manier nodig om elk van deze klassen te "registreren" als eindpunt in onze HTTP-server. Laten we een eenvoudige functie maken om dat te regelen. Onze functie krijgt een klasse als argument en voegt een instantie van die klasse toe als eindpunt aan onze server. Zoals zo:

Zonder dat je het doorhad, schreven we al onze eerste decorateur! Dat klopt, zo simpel is het. Het enige dat een decorateur is, is een functie die een klasse als argument neemt, en hier hebben we het. In plaats van registerEndpoint op de "normale" manier aan te roepen, kunnen we onze klassen gewoon decoreren met @registerEndpoint. geloof me niet? Even kijken:

We hebben onze eerste decorateur in gebruik genomen en het kostte ons maar 2 minuten of zo. We zijn nu klaar om dieper te duiken en de kracht van de methode-decorateur te ontketenen.

Ontketen de kracht van de methode Decorator

Laten we zeggen dat we sommige van onze eindpunten willen beschermen, zodat alleen geverifieerde gebruikers toegang hebben. Om dat te doen, kunnen we een nieuwe decorateur maken, genaamd protect. Voorlopig hoeft onze decorateur alleen de beveiligde methode toe te voegen aan een array met de naam protectedMethods.

Zoals u ziet, heeft de methode-decorateur 3 argumenten:

  1. target - Het prototype van onze klasse (of de constructor van de klasse als de gedecoreerde methode statisch is).
  2. propertyKey - De naam van de gedecoreerde methode.
  3. descriptor - Een object dat de gedecoreerde functie en enkele metagegevens bevat.

Tot nu toe lezen we alleen informatie over de klassen en methoden die we hebben ingericht, maar het echte plezier begint wanneer we hun gedrag beginnen te veranderen. We kunnen dat doen door eenvoudig een waarde van de decorateur te retourneren. Wanneer een methode-decorateur een waarde retourneert, wordt deze waarde gebruikt in plaats van de oorspronkelijke descriptor (die de oorspronkelijke methode bevat).

Laten we het proberen door een decorateur te maken met de naam nope, die onze oorspronkelijke methode vervangt door een methode die 'nope' afdrukt wanneer deze wordt aangeroepen. Om dit te doen, overschrijf ik descriptor.value, waar de oorspronkelijke functie is opgeslagen, met mijn functie:

Op dit punt hebben we gespeeld met de basisprincipes van methode-decorateurs, maar hebben nog niets nuttigs gemaakt. Wat ik nu ga doen, is de protect decorateur herschrijven, maar deze keer in plaats van alleen de namen van de gedecoreerde methoden te loggen, zal het feitelijk ongeautoriseerde verzoeken blokkeren.

Deze volgende stap zal een beetje ingewikkelder zijn dan de laatste, dus houd mij vol. Dit zijn de stappen die we moeten nemen:

  1. Pak de oorspronkelijke functie uit de descriptor en bewaar deze ergens anders voor later gebruik.
  2. Overschrijf descriptor.value met een nieuwe functie die dezelfde argumenten als het origineel aanneemt.
  3. Controleer in onze nieuwe functie of het verzoek is geverifieerd en of er geen fout is opgetreden.
  4. Tot slot, ook binnen onze nieuwe functie, kunnen we nu de oorspronkelijke functie met de benodigde argumenten aanroepen, de retourwaarde vastleggen en retourneren.

Verbazingwekkend! We hebben een volledig operationele protect decorateur. Nu is het toevoegen of verwijderen van bescherming van onze methoden een fluitje van een cent.

Merk op hoe we in regel 8 de oorspronkelijke functie hieraan binden, zodat deze toegang heeft tot de instantie van zijn klasse. Zonder deze regel zou onze methode get () bijvoorbeeld this.houses niet kunnen lezen.

We zijn een heel eind op weg, maar er staat ons nog meer te wachten. Op dit punt moedig ik je aan om even de tijd te nemen en ervoor te zorgen dat je alles begrijpt wat we tot nu toe hebben gedaan. Om het u gemakkelijker te maken, heb ik alle bovenstaande code in de speeltuin hier geplaatst, zodat u deze kunt uitvoeren, wijzigen en breken totdat u het gevoel heeft dat u hem volledig begrijpt.

Krijg meer kracht met decoratorfabrieken

Laten we zeggen dat we nu een nieuw eindpunt willen toevoegen om de Stark-gezinsleden te retourneren, op het pad / families / stark / leden. Natuurlijk kunnen we geen klas met die naam maken, dus wat gaan we doen?

Wat we hier nodig hebben, is een manier om parameters door te geven die het gedrag van onze decorateurfunctie bepalen. Laten we onze goede oude registerEndpoint-decorateur nog eens bekijken:

Om parameters naar onze decorateur te sturen, moeten we het transformeren van een gewone decorateur naar een decorateurfabriek. Een decorateurfabriek is een functie die een decorateur retourneert. Om er een te maken, hoeven we onze originele decorateur als volgt in te pakken:

Nu kunnen we ook onze protect-decorateur inpakken, zodat deze het verwachte token als parameter krijgt:

Gevolgtrekking

Op dit punt heb je een goed begrip van decorateurs, hoe ze werken, evenals de kracht en expressiviteit die ze ons als programmeurs toestaan. In dit artikel besprak ik de meest bruikbare en meest voorkomende technieken, maar er is nog veel meer te leren. Decorateurs in Typescript kunnen niet alleen op klassen en methoden worden toegepast, maar ook op eigenschappen van klassen en methode-argumenten. Ik hoop dat je met je nieuw verworven begrip van decorateurs het gemakkelijk uit de documentatie kunt halen. Zoals altijd leg ik alle code van dit artikel in de speeltuin, dus speel maar!

ja, je hebt het gedaan!

Als je van dit artikel hebt genoten, voel je dan vrij om ervoor te klappen, zodat meer mensen het zullen vinden en er ook van genieten, en als je meer van de dingen wilt zien die ik schrijf, ben je van harte welkom om mij te volgen. Laat het me in de comments weten als je nog vragen hebt.

Misschien wilt u ook mijn andere TypeScript-artikelen over generieke en augmentatie of over klassenontwerp bekijken.