Wat is TypeScript en waarom zou ik het gebruiken in plaats van JavaScript?

Kunt u alstublieft beschrijven wat de TypeScript-taal is?

Wat kan het doen dat JavaScript of beschikbare bibliotheken niet kunnen, wat mij reden zou geven het te overwegen?

Oplossing

Ik schreef dit antwoord oorspronkelijk toen Typescript nog heet-van-de-persen was. Vijf jaar later is dit een OK overzicht, maar kijk

naar Lodewijk's antwoord hieronder voor meer diepgang

1000ft view...

[TypeScript][1] is een superset van JavaScript die vooral voorziet in optionele statische typering, klassen en interfaces. Een van de grote voordelen is dat IDE's een rijkere omgeving kunnen bieden voor het opsporen van veel voorkomende fouten *terwijl je de code typt*.

Om een idee te krijgen van wat ik bedoel, bekijk Microsoft's inleidende video over de taal.

Voor een groot JavaScript-project kan het gebruik van TypeScript resulteren in robuustere software, die toch kan worden ingezet waar een gewone JavaScript-applicatie zou draaien.

Het is open source, maar je krijgt alleen de slimme Intellisense terwijl je typt als je een ondersteunde IDE gebruikt. Aanvankelijk was dit alleen Microsoft's Visual Studio (ook opgemerkt in blog post van Miguel de Icaza). Tegenwoordig bieden andere IDE's ook ondersteuning voor TypeScript.

Zijn er nog meer van dit soort technologieën?

Er'is [CoffeeScript][5], maar dat dient echt een ander doel. IMHO, CoffeeScript biedt leesbaarheid voor mensen, maar TypeScript biedt ook diepe leesbaarheid voor *tools* door zijn optionele statische typering (zie deze [recente blog post][6] voor een beetje meer kritiek). Er is ook [Dart][7] maar dat is een volwaardige vervanging voor JavaScript (hoewel het [JavaScript-code kan produceren][8])

Voorbeeld

Als voorbeeld, hier's wat TypeScript (je kunt hiermee spelen in de TypeScript Playground)

class Greeter {
    greeting: string;
    constructor (message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}  

En hier's het JavaScript dat het zou produceren

var Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

Merk op hoe het TypeScript het type van lidvariabelen en parameters van klassemethoden definieert. Dit wordt verwijderd bij het vertalen naar JavaScript, maar gebruikt door de IDE en de compiler om fouten op te sporen, zoals het doorgeven van een numeriek type aan de constructor.

Het is ook in staat om types af te leiden die niet expliciet zijn gedeclareerd, bijvoorbeeld, het zou bepalen dat de greet() methode een string retourneert.

Debuggen van Typescript

Veel browsers en IDE's bieden directe debug ondersteuning via sourcecemaps. Zie deze Stack Overflow-vraag voor meer details: [TypeScript code debuggen met Visual Studio][10]

Wil je meer weten?

Ik schreef dit antwoord oorspronkelijk toen Typescript nog in de kinderschoenen stond. Kijk eens naar [Lodewijk's antwoord][11] op deze vraag voor wat meer actuele details.
Commentaren (28)

TypeScript's relatie tot JavaScript

TypeScript is een getypte superset van JavaScript die compileert naar gewone

JavaScript - typescriptlang.org. JavaScript is een programmeertaal die wordt ontwikkeld door EMCA's Technical Committee 39, een groep mensen die bestaat uit veel verschillende belanghebbenden. TC39 is een comité dat ondergebracht is bij ECMA: een interne normalisatie-organisatie. JavaScript kent veel verschillende implementaties door veel verschillende leveranciers (bijv. Google, Microsoft, Oracle, enz.). Het doel van JavaScript is de lingua franca van het web te worden. TypeScript is een superset van de JavaScript-taal die een enkele open-source compiler heeft en hoofdzakelijk door één enkele leverancier wordt ontwikkeld: Microsoft. Het doel van TypeScript is om fouten vroegtijdig op te sporen via een typesysteem en om JavaScript-ontwikkeling efficiënter te maken. In wezen bereikt TypeScript zijn doelstellingen op drie manieren:

  1. Ondersteuning voor moderne JavaScript-functies - De JavaScript-taal (niet de runtime) is gestandaardiseerd via de ECMAScript standaarden. Niet alle browsers en JavaScript-runtimes ondersteunen alle functies van alle ECMAScript-standaarden (zie dit overzicht). TypeScript maakt het gebruik van veel van de nieuwste ECMAScript-functies mogelijk en vertaalt deze naar oudere ECMAScript-targets van uw keuze (zie de lijst met compileertargets onder de --target compileroptie). Dit betekent dat u veilig gebruik kunt maken van nieuwe functies, zoals modules, lambda functies, klassen, de spread operator en destructurering, terwijl u achterwaarts compatibel blijft met oudere browsers en JavaScript runtimes.
  2. Geavanceerd typesysteem - De typeondersteuning maakt geen deel uit van de ECMAScript-standaard en zal dat waarschijnlijk ook nooit worden vanwege de geïnterpreteerde aard in plaats van de gecompileerde aard van JavaScript. Het typesysteem van TypeScript is ongelooflijk rijk en omvat: interfaces, enums, hybride types, generics, union/intersection types, access modifiers en nog veel meer. De officiële website van TypeScript geeft een overzicht van deze functies. Typescript's type systeem is op gelijke voet met de meeste andere getypte talen en in sommige gevallen aantoonbaar krachtiger.
  3. Developer tooling support - TypeScript's compiler kan draaien als een achtergrondproces om zowel incrementele compilatie als IDE-integratie te ondersteunen, zodat u gemakkelijker kunt navigeren, problemen kunt identificeren, mogelijkheden kunt inspecteren en uw codebase kunt refactoren.

    TypeScript's relatie met andere JavaScript-talen

    TypeScript heeft een unieke filosofie in vergelijking met andere talen die compileren naar JavaScript. JavaScript-code is geldige TypeScript-code; TypeScript is een superset van JavaScript. U kunt uw .js bestanden bijna hernoemen naar .ts bestanden en TypeScript gaan gebruiken (zie "JavaScript interoperabiliteit" hieronder). TypeScript-bestanden worden gecompileerd tot leesbaar JavaScript, zodat migratie terug mogelijk is en het begrijpen van het gecompileerde TypeScript helemaal niet moeilijk is. TypeScript bouwt voort op de successen van JavaScript en verbetert tegelijk de zwakke punten ervan. Aan de ene kant heb je toekomstbestendige tools die moderne ECMAScript-standaarden gebruiken en deze compileren naar oudere JavaScript-versies, waarvan Babel de populairste is. Aan de andere kant heb je talen die totaal verschillen van JavaScript en die JavaScript als doel hebben, zoals CoffeeScript, Clojure, Dart, Elm, Haxe, Scala.js, en nog een heleboel andere (zie deze lijst). Deze talen, hoewel ze misschien beter zijn dan waar JavaScript's toekomst ooit heen zou kunnen leiden, lopen een groter risico dat ze niet genoeg geadopteerd worden om hun toekomst te garanderen. Je zou ook meer moeite kunnen hebben om ervaren ontwikkelaars te vinden voor sommige van deze talen, hoewel degenen die je zult vinden vaak enthousiaster kunnen zijn. Interop met JavaScript kan ook een beetje meer betrokken zijn, omdat ze verder verwijderd zijn van wat JavaScript eigenlijk is. TypeScript zit tussen deze twee uitersten in, waardoor het risico in evenwicht is. TypeScript is in geen geval een riskante keuze. Het vergt weinig inspanning om eraan te wennen als je vertrouwd bent met JavaScript, aangezien het geen compleet andere taal is, uitstekende ondersteuning biedt voor JavaScript-interoperabiliteit en het de laatste tijd veel gebruikt wordt.

    Optioneel statisch typen en type-inferentie

    JavaScript is dynamisch getypeerd. Dit betekent dat JavaScript niet weet welk type een variabele is totdat hij daadwerkelijk geïnstantieerd wordt tijdens runtime. Dit betekent ook dat het te laat kan zijn. TypeScript voegt typeondersteuning toe aan JavaScript. Bugs die worden veroorzaakt door onjuiste aannames dat een variabele van een bepaald type is, kunnen volledig worden geëlimineerd als je je kaarten goed speelt (hoe strikt je je code typt of als je je code überhaupt typt, is aan jou). TypeScript maakt typen een beetje makkelijker en een stuk minder expliciet door het gebruik van type-inferentie. Bijvoorbeeld: var x = "hello" in TypeScript is hetzelfde als var x : string = "hello". Het type wordt gewoon afgeleid uit het gebruik. Ook al typ je de types niet expliciet, ze zijn er toch om je te behoeden iets te doen wat anders een runtime error zou opleveren. TypeScript is standaard optioneel getypeerd. Bijvoorbeeld functie divideByTwo(x) { return x / 2 } is een geldige functie in TypeScript die kan worden aangeroepen met elke soort parameter, ook al zal het aanroepen met een string uiteraard resulteren in een runtime fout. Net zoals je gewend bent in JavaScript. Dit werkt, omdat als er geen expliciet type is toegewezen en het type niet kon worden afgeleid, zoals in het deelBinnenTwee voorbeeld, TypeScript impliciet het type any zal toewijzen. Dit betekent dat de type signature van de functie divideByTwo'automatisch functie divideByTwo(x : any) : any wordt. Er is een compiler vlag om dit gedrag uit te schakelen: --noImplicitAny. Het inschakelen van deze flag geeft je een grotere mate van veiligheid, maar betekent ook dat je meer moet typen. Types hebben een prijs. Ten eerste is er een leercurve, en ten tweede kost het je natuurlijk ook wat meer tijd om een codebase op te zetten die de juiste strikte typering gebruikt. In mijn ervaring zijn deze kosten het helemaal waard op elke serieuze codebase die je deelt met anderen. A Large Scale Study of Programming Languages and Code Quality in Github suggereert dat "statisch getypeerde talen, in het algemeen, minder defectgevoelig zijn dan de dynamische types, en dat sterke typing beter is dan zwakke typing in hetzelfde opzicht". Het is interessant op te merken dat in ditzelfde artikel wordt vastgesteld dat TypeScript minder foutgevoelig is dan JavaScript: Voor degenen met positieve coëfficiënten kunnen we verwachten dat de taal geassocieerd is met, ceteris paribus, een groter aantal defect fixes. Deze talen omvatten C, C++, JavaScript, Objective-C, Php, en Python. De talen Clojure, Haskell, Ruby, Scala, en TypeScript, hebben allemaal negatieve coëfficiënten, wat betekent dat deze talen minder dan het gemiddelde om te resulteren in defect reparerende commits.

    Verbeterde IDE-ondersteuning

    De ontwikkelervaring met TypeScript is een grote verbetering ten opzichte van JavaScript. De IDE wordt in realtime door de TypeScript-compiler geïnformeerd over de rijke type-informatie. Dit geeft een paar grote voordelen. Met TypeScript kun je bijvoorbeeld veilig refactorings zoals hernoemingen uitvoeren in je hele codebase. Via code completion kunt u inline hulp krijgen bij alle functies die een bibliotheek aanbiedt. U hoeft ze niet meer te onthouden of op te zoeken in online referenties. Compilatiefouten worden direct in de IDE gemeld met een rode kronkelende lijn terwijl u bezig bent met coderen. Al met al zorgt dit voor een aanzienlijke productiviteitswinst ten opzichte van het werken met JavaScript. Men kan meer tijd besteden aan het coderen en minder aan het debuggen. Er is een breed scala aan IDE's die uitstekende ondersteuning bieden voor TypeScript, zoals Visual Studio Code, WebStorm, Atom en Sublime.

    Strikte null-controles

    Runtime errors van de vorm cannot read property 'x' of undefined of undefined is not a function worden heel vaak veroorzaakt door bugs in JavaScript code. Out of the box TypeScript verkleint de kans op dit soort fouten al, omdat men geen variabele kan gebruiken die niet bekend is bij de TypeScript compiler (met uitzondering van eigenschappen van any getypeerde variabelen). Het is echter nog steeds mogelijk om per ongeluk een variabele te gebruiken die is ingesteld op undefined. Met de 2.0 versie van TypeScript kun je dit soort fouten elimineren door het gebruik van niet-nullable types. Dit werkt als volgt: Met strikte nulcontroles ingeschakeld (--strictNullChecks compiler flag) zal de TypeScript compiler niet toestaan dat undefined wordt toegewezen aan een variabele, tenzij je deze expliciet als een nullable type declareert. Bijvoorbeeld, let x : getal = ongedefinieerd zal resulteren in een compileerfout. Dit past perfect in de typetheorie omdat undefined geen getal is. Men kan x definiëren als een somtype van getal en undefined om dit te corrigeren: let x : getal | undefined = undefined. Als eenmaal bekend is dat een type nullable is, wat betekent dat het van een type is dat ook de waarde null of undefined kan hebben, kan de TypeScript compiler door middel van control flow gebaseerde type analyse bepalen of je code veilig een variabele kan gebruiken of niet. Met andere woorden als je controleert of een variabele undefined is door bijvoorbeeld een if statement zal de TypeScript compiler afleiden dat het type in die tak van je code's control flow niet meer nullable is en dus veilig gebruikt kan worden. Hier is een eenvoudig voorbeeld:

let x: number | undefined;
if (x !== undefined) x += 1; // this line will compile, because x is checked.
x += 1; // this line will fail compilation, because x might be undefined.

Tijdens de build, 2016 conferentie gaf mede-ontwerper van TypeScript Anders Hejlsberg een gedetailleerde uitleg en demonstratie van deze functie: video (van 44:30 tot 56:30).

Compilatie

Om TypeScript te gebruiken, heb je een buildproces nodig om naar JavaScript-code te compileren. Het compilatieproces duurt meestal maar een paar seconden, afhankelijk van de grootte van uw project. De TypeScript-compiler ondersteunt incrementele compilatie (--watch compiler flag), zodat alle volgende wijzigingen sneller kunnen worden gecompileerd. De TypeScript-compiler kan inline source map-informatie in de gegenereerde .js-bestanden of aparte .map-bestanden maken. Bronmapinformatie kan worden gebruikt door debuggingprogramma's zoals de Chrome DevTools en andere IDE's om de regels in het JavaScript te relateren aan de regels die ze in het TypeScript hebben gegenereerd. Dit maakt het mogelijk voor u om breakpoints in te stellen en variabelen te inspecteren tijdens runtime, rechtstreeks op uw TypeScript-code. Source map informatie werkt vrij goed, het was er al lang voor TypeScript, maar het debuggen van TypeScript is over het algemeen niet zo geweldig als wanneer JavaScript direct wordt gebruikt. Neem bijvoorbeeld het this keyword. Door de veranderde semantiek van het this keyword rond closures sinds ES2015, kan this eigenlijk bestaan tijdens runtime als een variabele genaamd _this (zie dit antwoord). Dit kan u verwarren tijdens het debuggen, maar over het algemeen is het geen probleem als u het weet of de JavaScript code inspecteert. Opgemerkt moet worden dat Babel precies hetzelfde soort probleem heeft. Er zijn nog een paar andere trucs die de TypeScript-compiler kan doen, zoals het genereren van onderscheppingscode op basis van decorators, het genereren van code voor het laden van modules voor verschillende modulesystemen en het parseren van JSX. U zult echter waarschijnlijk een ander bouwgereedschap nodig hebben dan de Typescript compiler. Als je bijvoorbeeld je code wilt comprimeren, zul je andere tools aan je bouwproces moeten toevoegen om dat te doen. Er zijn TypeScript compilatie plugins beschikbaar voor Webpack, Gulp, Grunt en zowat elke andere JavaScript build tool die er is. De TypeScript-documentatie heeft een sectie over integreren met build-tools die ze allemaal bespreekt. Er is ook een linter beschikbaar voor het geval je nog meer controle op de bouwtijd wilt. Er zijn ook een groot aantal seed-projecten waarmee je aan de slag kunt met TypeScript in combinatie met een heleboel andere technologieën zoals Angular 2, React, Ember, SystemJS, Webpack, Gulp, enz.

interoperabiliteit van JavaScript

Omdat TypeScript zo nauw verwant is aan JavaScript heeft het geweldige interoperabiliteitsmogelijkheden, maar er is wat extra werk nodig om met JavaScript-bibliotheken in TypeScript te werken. TypeScript definities zijn nodig zodat de TypeScript compiler begrijpt dat functie-aanroepen zoals _.groupBy of angular.copy of $.fadeOut in feite geen illegale statements zijn. De definities voor deze functies worden in .d.ts bestanden geplaatst. De eenvoudigste vorm die een definitie kan aannemen is om een identifier toe te staan om op een willekeurige manier gebruikt te worden. Bijvoorbeeld, bij gebruik van Lodash, zal een enkele regel definitie-bestand declare var _ : any je toestaan om elke functie aan te roepen die je wilt op _, maar dan kun je natuurlijk ook nog fouten maken: _.foobar() zou een legale TypeScript aanroep zijn, maar is, natuurlijk, een illegale aanroep bij runtime. Als je goede type-ondersteuning en code completering wilt, moet je definitiebestand preciezer zijn (zie lodash definitions voor een voorbeeld). Npm-modules die voorverpakt zijn met hun eigen type-definities worden automatisch begrepen door de TypeScript-compiler (zie documentatie). Voor vrijwel elke andere semi-populaire JavaScript-bibliotheek die geen eigen definities bevat, heeft iemand al type-definities beschikbaar gemaakt via een andere npm-module. Deze modules worden voorafgegaan door "@types/" en komen uit een Github repository genaamd DefinitelyTyped. Er is één nadeel: de typedefinities moeten overeenkomen met de versie van de bibliotheek die u tijdens runtime gebruikt. Als dat niet het geval is, kan TypeScript je verbieden om een functie aan te roepen of een variabele te dereferencen die bestaat, of je toelaten om een functie aan te roepen of een variabele te dereferencen die niet bestaat, gewoon omdat de types niet overeenkomen met de run-time op compile-time. Zorg er dus voor dat je de juiste versie van de type-definities laadt voor de juiste versie van de bibliotheek die je gebruikt. Eerlijk gezegd is dit een beetje lastig en het kan een van de redenen zijn waarom je niet voor TypeScript kiest, maar in plaats daarvan voor iets als Babel dat helemaal geen last heeft van het moeten ophalen van type definities. Aan de andere kant, als je weet wat je doet, kun je gemakkelijk problemen oplossen die veroorzaakt worden door onjuiste of ontbrekende definitiebestanden.

Van JavaScript naar TypeScript converteren

Elk .js bestand kan worden hernoemd naar een .ts bestand en door de TypeScript compiler worden gehaald om syntactisch dezelfde JavaScript code als uitvoer te krijgen (als het tenminste syntactisch correct was). Zelfs als de TypeScript compiler compilatiefouten krijgt zal het nog steeds een .js bestand produceren. Hij kan zelfs .js bestanden als invoer accepteren met de --allowJs vlag. Hierdoor kunt u meteen met TypeScript aan de slag. Helaas is de kans groot dat er in het begin compilatiefouten optreden. Je moet wel onthouden dat dit geen show-stopping errors zijn zoals je misschien gewend bent van andere compilers.
De compilatiefouten die men in het begin krijgt bij het converteren van een JavaScript-project naar een TypeScript-project zijn onvermijdelijk door de aard van TypeScript's. TypeScript controleert alle code op geldigheid en moet dus op de hoogte zijn van alle functies en variabelen die worden gebruikt. Daarom moeten voor al deze functies en variabelen typedefinities bestaan, anders zullen er zeker compilatiefouten optreden. Zoals vermeld in het hoofdstuk hierboven, zijn er voor vrijwel elk JavaScript framework .d.ts bestanden die gemakkelijk verkregen kunnen worden met de installatie van DefinitelyTyped packages. Het kan echter zijn dat u een of andere obscure bibliotheek hebt gebruikt waarvoor geen TypeScript-definities beschikbaar zijn of dat u een aantal JavaScript-primitieven hebt gepolyfilled. In dat geval moet je type-definities voor deze bits leveren om de compilatiefouten te laten verdwijnen. Maak gewoon een .d.ts bestand en neem het op in de tsconfig.json's files array, zodat het altijd door de TypeScript compiler in aanmerking wordt genomen. Daarin declareer je de bits die TypeScript niet kent als type any. Als je eenmaal alle fouten hebt geëlimineerd kun je geleidelijk typing introduceren in die delen naar gelang je behoeften. Er zal ook wat werk aan de (her)configuratie van je bouwpijplijn nodig zijn om TypeScript in de bouwpijplijn te krijgen. Zoals vermeld in het hoofdstuk over compilatie zijn er veel goede bronnen beschikbaar en ik moedig je aan om op zoek te gaan naar seed-projecten die de combinatie van tools gebruiken waarmee je wilt werken. De grootste hindernis is de leercurve. Ik moedig je aan om eerst met een klein project te spelen. Kijk hoe het werkt, hoe het bouwt, welke bestanden het gebruikt, hoe het geconfigureerd is, hoe het functioneert in je IDE, hoe het gestructureerd is, welke tools het gebruikt, enz. Het omzetten van een grote JavaScript codebase naar TypeScript is te doen als je weet wat je doet. Lees bijvoorbeeld deze blog over het omzetten van 600k regels naar TypeScript in 72 uur). Zorg er alleen wel voor dat je de taal goed beheerst voordat je de sprong waagt.

Overname

TypeScript is open-source (Apache 2-licentie, zie GitHub) en wordt gesteund door Microsoft. Anders Hejlsberg, de hoofdarchitect van C# is de speerpunt van het project. Het is een zeer actief project; het TypeScript-team heeft de afgelopen jaren veel nieuwe functies uitgebracht en er staan nog veel geweldige functies op de planning (zie de roadmap). Enkele feiten over adoptie en populariteit:

  • In de 2017 StackOverflow developer survey was TypeScript de meest populaire JavaScript-transpiler (9e plaats overall) en won het de derde plaats in de categorie meest geliefde programmeertaal.
  • In de 2018 state of js survey werd TypeScript uitgeroepen tot een van de twee grote winnaars in de categorie JavaScript-smaakmakers (met ES6 als de andere).
  • In de 2019 StackOverlow deverloper survey steeg TypeScript naar de 9e plaats van meest populaire talen onder professionele ontwikkelaars, waarmee het zowel C als C++ inhaalde. Het nam opnieuw de derde plaats in onder de meest geliefde talen.
Commentaren (10)

"TypeScript Fundamentals" -- een Pluralsight video-cursus van Dan Wahlin en John Papa is een zeer goede, momenteel (25 maart 2016) bijgewerkte inleiding tot Typescript (TypeScript 1.8).

Voor mij zijn de echt goede eigenschappen, naast de mooie mogelijkheden voor intellisense, de klassen, interfaces, modules, het gemak van het implementeren van AMD, en de mogelijkheid om de Visual Studio Typescript debugger te gebruiken wanneer deze wordt aangeroepen met IE.

Om samen te vatten: Indien gebruikt zoals bedoeld, kan Typescript JavaScript programmeren betrouwbaarder maken, en eenvoudiger. Het kan de productiviteit van de JavaScript programmeur aanzienlijk verhogen over de volledige SDLC.

Commentaren (3)