Typescript

TypeScript is Microsofts oplossing om grote JavaScript applicaties op een beheerbare manier te kunnen ontwikkelen. In dit stuk gaan we ontdekken wat dit inhoud. Als eerst gaan in op de vraag wat TypeScript precies is en wat de ideeën er achter zijn. Vervolgens gaan we stap voor stap, vanuit JavaScript, in op het gebruik van types, classes en interfaces. Als laatste gaan we in op hoe we bestaande JavaScript libraries kunnen gebruiken in onze TypeScript code.

Wat is TypeScript

De premisse die aan TypeScript ten grondslag ligt, is dat het lastig is grote JavaScript codebases te ontwikkelen door het gebrek aan elementen om structuur aan te brengen. Daarnaast is er beperkte mogelijkheid voor IDE support doordat JavaScript geen type informatie bevat. De oplossing van Microsoft hiervoor is TypeScript.

TypeScript is geen vervanging voor JavaScript maar een toevoeging. TypeScript voegt elementen zoals classes, interfaces en modules toe aan JavaScript zodat het makkelijker wordt grote applicaties in onderdelen op te bouwen en te structureren. Daarnaast geeft TypeScript de mogelijkheid type informatie toe te voegen zodat in IDE’s dingen als code completion, find all references en refactoring mogelijk worden. Door de type informatie wordt het ook eenvoudiger om door codebases heen te navigeren doordat je eenvoudig de types kunt volgen.

Bij alles dat TypeScript toevoegt aan JavaScript proberen ze zo dicht mogelijk te blijven bij de specificaties van de nieuwe versie van JavaScript: ECMAScript 6. Voor een gedeelte programmeer je met TypeScript dus met het JavaScript van de toekomst.

Een superset van JavaScript gecompileerd naar JavaScript

Er zijn twee interessante dingen aan de opzet van TypeScript.

1. Het is een superset van JavaScript wat betekent dat geldige JavaScript eveneens geldige TypeScript is

2. Uiteindelijk wordt JavaScript uitgevoerd. De extra elementen die TypeScript toevoegt worden naar JavaScript gecompileerd en de resulterende JavaScript wordt uitgevoerd

Dit zorgt er onder andere voor dat je vanuit bestaande JavaScript code met TypeScript kunt beginnen (als je een stuk bestaande JavaScript als TypeScript gebruikt rolt het ongewijzigd de compiler door en werkt het gewoon). Daarnaast zorgt het ervoor dat je alle bestaande JavaScript libraries kunt gebruiken. Dus of je nu AngularJS, RxJS of Batman.js wil gebruiken, TypeScript zit je niet in de weg.

Van JavaScript naar TypeScript

Standaard JavaScript

Zoals vermeld is standaard JavaScript ook geldige TypeScript. Figuur 1 is een schermprint uit de Visual Studio typescript editor. Met deze editor kun je in het linker paneel typescript programmeren waarna het gecompileerd wordt en de resulterende JavaScript in het rechter paneel getoond wordt. De resulterende JavaScript is dat wat uiteindelijk uitgevoerd gaat worden. In figuur 1 hebben we een simpele JavaScript functie om twee getallen bij elkaar op te tellen met twee aanroepen. We zien dat de code één op één door de typescript compiler gaat.

 Figuur 1: JavaScript is TypeScript wordt JavaScript

Type informatie toevoegen

In de code van figuur 1 zit een bug. De intentie van onze ‘add’ functie is dat er twee getallen opgeteld worden. Er is echter een aanroep waarbij er twee strings worden meegegeven. Dit breekt het programma niet, maar het levert wel dubieuze output op.

Wat we met typescript kunnen doen is dat we de functie ‘add’ voorzien van type informatie. Bij de code in figuur 2 hebben we bij de parameters aangegeven dat er een ‘number’ verwacht wordt voor beide parameters en dat de functie ook een ‘number’ als resultaat geeft. Aan de linkerkant zien we dat de typescript compiler nu aangeeft dat in regel 6 de ‘add’ functie wordt aangeroepen met iets anders dan twee getallen.

 Figuur 2: Type informatie checkt je aanroepen

Door enkele types aan te geven hebben we onze code expressiever gemaakt en een bug ontdekt. Wat verder opvalt als we naar het rechter paneel kijken is dat er bij de resulterende JavaScript code niets veranderd is. De code wordt er dus niet zwaarder van en doet exact hetzelfde als de code zonder de extra typeringen. Het is puur voor het compileren.

Naast het detecteren van foutieve aanroepen krijgen we door de type informatie nu ook zinvolle code completion van de IDE. In figuur 3 zien we bij het aanroepen van de add methode dat de IDE al aangeeft wat er verwacht wordt. En vanuit deze aanroep kunnen we eenvoudig naar de functiedefinitie navigeren.

 Figuur 3: Code completion dankzij type informatie

Structureren

TypeScript bevat ook verschillende elementen om structuur in je code aan te brengen en je te helpen tijdens het ontwikkelen. Bijvoorbeeld classes en interfaces. In figuur 4 zien we een class voor een persoon. Een instantie van persoon kun je aanmaken via de constructor waarbij in dit geval een naam moet worden meegegeven. Op de persoon class zit een methode om een bericht aan de persoon te sturen (sendMessage). Hierbij is met type informatie aangegeven dat de message moet voldoen aan de IMessage interface die bovenin gedefinieerd is.

Het checken van de interfaces doet TypeScript puur op de structuur. Bij het aanroepen van de sendMessage methode hoeft er niet een instantie van een class meegegeven worden die de IMessage interface implementeert, als dat wat wordt meegestuurd maar voldoet aan de interface. In dit geval dwingt de interface af dat er een sendDate moet worden meegegeven van het type Date en text met als type string. Dat gebeurt in dit geval dus dan vind de compiler het goed.

 Figuur 4: Heldere code met interfaces, classes en types

Wat je in figuur 4 verder kan zien is dat in dit geval het verschil tussen de geprogrammeerde TypeScript code links en de gegenereerde JavaScript code rechts groter wordt. De type informatie verdwijnt (want dat kent JavaScript niet). Daarnaast zie je interface niet meer terug. De interface zorgt er alleen voor dat je tijdens het programmeren geholpen wordt en dat de compiler kan checken of bij alle aanroepen de juiste elementen worden meegegeven.

Als je naar de JavaScript kijkt is dit dezelfde compacte code die je zelf zou schrijven. Voor de performance maakt de extra structuur in de TypeScript code dus niet uit.

Externe libraries gebruiken

Eén van de goede punten van TypeScript is dat je, omdat het allemaal JavaScript is, gebruik kunt maken van alle bestaande JavaScript libraries. Je mist dan wel de extra type informatie en de daaraan gekoppelde code completion maar wat je uiteindelijk overhoudt is gewone JavaScript zoals we gewend zijn.

Wat met TypeScript ook mogelijk is, is dat je een beschrijving maakt van een bestaand library. Je omschrijft dan met TypeScript interfaces en classes de API van de library die je gebruikt. In TypeScript worden dit definitie files genoemd. Er wordt dus geen code vertaald naar TypeScript of omgezet, maar alleen de structuur van de API van de library wordt beschreven zodat de TypeScript compiler en IDE weten hoe je de library kunt gebruiken. Tijdens het uitvoeren worden gewoon de standaard JavaScript libraries gebruikt.

In figuur 5 zien een een klein stukje van een definitie file en het gebruik er van. Links zien we een fragment uit de definitie van Reactive extensions (RxJS) waarin omschreven is dat een IObserver<T> een OnNext, OnError en OnCompleted methode hebben inclusief de verdere type informatie. In het fragment in het midden zien we dat we dankzij deze informatie goede code completion hebben in de IDE en dat hij de bug heeft ontdekt dat we een getal in de onNext meegeven terwijl de observable het generic type string heeft. Rechts zien we resulterende JavaScript, standaard RxJS JavaScript.

Figuur 5: Gebruik van de definitie files van Rx

Het maken van definities van bestaande JavaScript libraries is flink wat werk, maar dankzij de inzet van de community zijn er voor de meest gangbare libraries al definitie files (https://github.com/borisyankov/DefinitelyTyped). En bij bijvoorbeeld RxJS worden ze standaard meegeleverd.

Conclusie

TypeScript is gewoon JavaScript maar dan met structuur. We hebben gezien hoe je met TypeScript door het gebruik van types eenvoudig fouten uit je code kunt halen, hoe de type informatie, classes en interfaces je helpen de intentie van de code te communiceren en hoe het bijvoorbeeld code completion van je IDE mogelijk maakt. En wellicht het belangrijkste, dat je nog steeds alle bestaande JavaScript libraries kunt gebruiken die er zijn en vaak nog met alle TypeScript voordelen dankzij de definitie files. TypeScript is nog steeds JavaScript en dat kun je ook als een nadeel ervaren. Veel van de rariteiten van JavaScript blijven bestaan zoals het gebruik van this.

Naast de besproken onderdelen zit er nog meer in TypeScript. Kijk hiervoor bijvoorbeeld naar http://www.typescriptlang.org/Handbook of https://www.youtube.com/watch?v=IRunqezn4pQ.

Als je het internet afzoekt zijn er meningen en argumenten genoeg te vinden voor en tegen TypeScript. Persoonlijk vind ik type informatie enorm waardevol en helpt het mij bijvoorbeeld in het leren van AngularJS. Dankzij de goede definitiefiles die er voor AngularJS zijn krijg ik goede code completion waardoor ik veel minder vaak de API documentatie in hoef te duiken om uit te zoeken wat er allemaal mogelijk is. Of het ook iets voor jou is mag je zelf beslissen.

[[ In de interne nieuwsbrief van Sogyo schrijf ik, onder de titel ‘gave technologie’, over technologiën waar ik enthousiast over ben en waarvan ik vind dat iedere collega op zijn minst moet weten dat het bestaat. Dit artikel komt uit de Sogyo Nieuwsbrief van juli 2014 ]]