JSDoc ist TypeScript
(culi.bearblog.dev)- Ein Refactoring-PR im Svelte-Repository sorgte 2023 für Aufmerksamkeit unter TypeScript-Skeptikern, als auf JSDoc-basierten Code umgestellt wurde
- Svelte erklärte, dies sei keine anti-TypeScript-Haltung, sondern Teil einer fortgesetzten Abhängigkeit von TypeScript
- Der Text betont, dass JSDoc und TypeScript kein Gegensatz sind, sondern dass JSDoc selbst ein Teil von TypeScript ist
- TypeScript fungiert als IntelliSense-Engine und übernimmt sowohl die Auswertung von JSDoc-Kommentaren als auch die automatische Codevervollständigung
- JSDoc bietet ohne Build-Schritt dieselben statischen Analysefähigkeiten und erfüllt in modernen JS-Projekten praktisch die gleiche Rolle wie TypeScript
Der Svelte-PR und der Hintergrund der Debatte
- Im Mai 2023 schaffte es ein internes Refactoring-PR aus dem Svelte-Repository auf die Startseite von Hacker News
- In diesem PR wurden Typdeklarationen aus
.ts-Dateien in JSDoc-Kommentare innerhalb von.js-Dateien verlagert - Manche interpretierten das als Ablehnung der Vorteile von TypeScript
- In diesem PR wurden Typdeklarationen aus
- Svelte-Gründer Rich Harris erklärte auf HN selbst: „Das ist nicht gegen TypeScript gerichtet“
- Er erwähnte, dass Sveltes Bekenntnis zu TypeScript weiterhin sehr stark ist
- Danach erschienen zahlreiche Beiträge zum Vergleich „TypeScript vs. JSDoc“, und die Sichtweise verbreitete sich, JSDoc sei „TypeScript ohne Build-Schritt“
Ursprung und Wesen von TypeScript
- Ende der 2000er bis Anfang der 2010er Jahre galt JavaScript als Sprache mit zu wenig Autovervollständigung und Typsicherheit
- Microsoft-Entwickler begegneten dem, indem sie mit ScriptSharp C#-Code in JS umwandelten
- Vor diesem Hintergrund entstand TypeScript und startete seinem Wesen nach als Build-Tool zur Verbesserung der JS-Entwicklung
TypeScript ist IntelliSense
- TypeScript ist nicht nur eine Sprache, sondern fungiert als IntelliSense-Engine
- Auch ohne
.ts-Dateien werden Funktionen wie Codevervollständigung, Parameterinformationen und Symbolnavigation vom TypeScript-Sprachdienst bereitgestellt - In den meisten Editoren läuft beim Schreiben von JS-Code der TypeScript-Dienst im Backend
- Auch ohne
TypeScript ist JSDoc
- Der TypeScript-Sprachdienst wird auch für die Auswertung von JSDoc-Kommentaren verwendet
- Im CHANGELOG von TypeScript finden sich häufig Einträge zu neuen JSDoc-Funktionen
- Auch JSDoc-basierte Projekte lassen sich mit
tsconfig.jsonkonfigurieren, und mit dem Befehltscist eine Typprüfung möglich
- Entwickler, die JSDoc verwenden, nutzen also bereits TypeScript
Erfahrungen mit JSDoc-basierten Projekten
- Der Autor berichtet von der Erfahrung, das Frontend eines bestehenden Projekts auf Basis von JSDoc-Typkommentaren neu geschrieben zu haben
- Abgesehen von Laufzeitfunktionen wie Enums (
enum) lässt sich der Großteil der TypeScript-Ausdrucksmöglichkeiten auch mit JSDoc umsetzen - Generics haben eine etwas kompliziertere Syntax, fördern dafür aber eine aktivere Nutzung der Typinferenz
- Abgesehen von Laufzeitfunktionen wie Enums (
- In JSDoc-Projekten kann man beim Klick auf eine Funktion direkt zum tatsächlichen Code springen, was die Developer Experience verbessert
- Das TypeScript-Tooling-Ökosystem lässt sich auch in JSDoc-Projekten wiederverwenden
- Zum Beispiel können Bibliotheken, die Typen aus OpenAPI- oder GraphQL-Schemata generieren, diese als JSDoc-Kommentare erzeugen
Fazit und weitere Beispiele
- JSDoc ist keine Alternative zu TypeScript, sondern teilt sich dasselbe System statischer Analyse
- Es ermöglicht gleichwertige Typsicherheit, während der Build-Schritt entfällt
- Zusätzlich wird erwähnt, dass auch das webpack-Projekt auf JSDoc migriert wurde
- Als TypeScript-Experte vertritt der Autor klar die Position: „JSDoc ist TypeScript“
1 Kommentare
Hacker-News-Kommentare
Über mehrere Jahre hinweg habe ich beim Entwickeln und Warten von Web- und Robotiksoftware mit Python/JavaScript einiges gelernt.
Typen existieren auch dann, wenn man sie nicht explizit angibt, und wenn man sie nicht angibt, existieren sie am Ende nur im Kopf.
Aber der Kopf ist vergänglich und für andere schwer zugänglich.
Deshalb ist Typisierung ein hervorragendes Mittel zur Dokumentation.
JSDoc und TypeScript sind Standardformate, um Typen auszudrücken, und beide haben Vor- und Nachteile.
Wichtig ist, Typen konsistent und vorhersehbar zu definieren.
Ein Type Checker ist die Art, wie der Computer sagt: „Dann beweise es.“
Nicht jedes Programm braucht dasselbe Maß an Beweisen, und übermäßiges Beweisen kann Verschwendung sein.
Deshalb bevorzuge ich Sprachen, in denen ich nur so weit „beweisen“ muss, wie es nötig ist.
Gerade bei der Arbeit habe ich schmerzhaft gelernt, dass zu den „anderen Menschen“ auch mein zukünftiges Ich gehört.
Mit Rust kann man Einschränkungen über unsafe, Arc, clone und Ähnliches lockern, muss dann aber bewusst festlegen, welche Einschränkungen nicht bewiesen wurden.
Bei Sprachen, in denen man „nicht beweisen muss“, ist dagegen schwer zu erkennen, welchen internen Ansatz sie gewählt haben.
Rusts Ansatz erlaubt anfangs ein lockeres Arbeiten wie in Python, ist später aber bei Lesbarkeit und Skalierbarkeit deutlich im Vorteil.
Es war nicht meine Absicht, ein bestimmtes Tool zu verteidigen, sondern nur zu betonen, dass beide Ausdrucksformen eines Typsystems sind.
Statisch typisierte Sprachen waren in Teamprojekten viel einfacher zu handhaben, und auch heute bevorzuge ich nach Möglichkeit statische Typen.
Wenn man sich die nachträglich zu bestehenden JS-Bibliotheken hinzugefügten TypeScript-Typdefinitionen ansieht, ist die Komplexität enorm.
Schon ein einzelner falscher Typ kann den gesamten Build zerstören.
Am Ende muss man dynamische Sprachen auf eine Weise verwenden, bei der man selbst Verantwortung übernimmt.
Ich mag alles, was sich in JavaScript ohne Build-Schritt erstellen lässt.
Modernes HTML/CSS, Web Components und JSDoc zusammen werden unterschätzt.
Es ist nicht für alle geeignet, aber ich halte es für einen ausreichend modernen Kandidaten für einen Frontend-Stack.
Dank Funktionen wie HMR sind die Kosten eines Build-Schritts auch stark gesunken.
Es geht immer durch Vite oder Webpack, daher spüre ich die Vorteile von buildlosem JS nicht wirklich.
Ich wünschte, es gäbe eine einfache Möglichkeit, komplexe Komponenten zu erstellen.
Das Nachverfolgen von Netzwerk-Requests, direktes Springen zum Quellcode, Setzen von Breakpoints und Ähnliches macht das Debugging viel intuitiver.
Je größer das Projekt wird, desto wertvoller wird so eine Umgebung.
Als SPAs in Mode waren, war JSDoc der Retter beim Typmanagement.
Danach kam der Google Closure Compiler und bot typbasierte Sicherheit auf JSDoc-Basis, und TypeScript unterstützte (TS)JSDoc zusammen mit eigener Syntax.
Die Community entschied sich am Ende für TypeScript, und der Closure Compiler verschwand.
Dadurch blieb (TS)JSDoc als Relikt aus der Zeit, als MS mit Google konkurrierte, zurück.
Heute bietet TS viel mehr Funktionen wie Generics, Enums, Utility-Typen, Vitest-Typtests, Type Guards usw.
Ich verwende TS und JSDoc zusammen — TS für den Code, JSDoc für die Dokumentation (@link, @see, @deprecated, @example usw.).
Generics, Utility-Typen, Type Guards, RegEx-Parsing und die meisten anderen TS-Funktionen lassen sich auch in JSDoc nutzen.
Ich habe in einem privaten Projekt sogar alles einschließlich Generics komplett mit JSDoc umgesetzt.
Dass (TS)JSDoc ein Relikt der Vergangenheit sei, ist Fehlinformation und sollte nicht ungeprüft weiterverbreitet werden.
Es heißt zwar, es gebe viele Typen, die sich mit JSDoc nicht ausdrücken lassen, aber ich hätte mir gewünscht, es wäre mit einem ganzheitlichen Sprachansatz wie bei Flow möglich gewesen.
TypeScript hätte das auch tun können, aber ich weiß nicht, warum es das nicht getan hat.
Ich habe früher auch so gedacht, aber beim Refactoring eines Projekts auf JSDoc habe ich meine Meinung geändert.
In JSDoc kann man mit
@templategenerische Slots definieren.Beispiel:
Relevanter Link
Mit JSDoc geschriebene Pakete bieten eine gute Developer Experience, weil man mit CMD/CTRL-Klick direkt zum echten Code springen kann.
Vor 5 Jahren sagte ein Sprecher auf einem Meetup: „Wenn du TypeScript nicht magst, ist JSDoc eine Alternative.“
Ich erklärte, dass beides letztlich TypeScript sei, aber mein Chef glaubte mir nicht.
JSDoc und TS drücken beide Typen explizit aus, aber die TS-Syntax ist deutlich mächtiger.
Trotzdem ist JSDoc eine gute Wahl für Leute, die ihre JS-Umgebung beibehalten und zugleich von Typwerkzeugen profitieren wollen.
Als Gegenargument: JSDoc ist nicht TypeScript.
Mit
@typedefdefinierte Typen werden automatisch exportiert, und es gibt keine Möglichkeit, das zu steuern.Relevantes Issue
Deshalb war es bei der Entwicklung von Bibliotheken lästig, dass IntelliSense unübersichtlich offengelegt wurde.
Man kann die Datei „my-component.js“ einfach so kopieren, und sie funktioniert ohne Build.
In großen Projekten bevorzuge ich aber die TS-Syntax.
Ich stimme der Aussage zu, dass „JSDoc keine Alternative zu TypeScript ist“.
JSDoc bietet ebenfalls statische Analyse, aber ohne Build-Schritt.
Siehe Node-Dokumentation.
TS auf JSDoc-Basis funktioniert jedoch auch im Browser.
Ich persönlich bevorzuge die Lesbarkeit der TS-Syntax, und mit Tools wie
swcist das Entfernen von Typen schnell genug.Der Grund, warum sich TypeScript gegenüber anderen Alternativen durchgesetzt hat, ist, dass es keine neue Sprache wurde, sondern ein Type Checker blieb.
Anfangs schwankte die Richtung etwas, aber das wurde passend korrigiert, und heute werden in den meisten Codebases nicht einmal Enums besonders häufig verwendet.
In VSCode kann man mit der Einstellung „TypeScript: Prefer Go To Source Definition“ direkt zur echten Quelle springen.
Außerdem funktioniert es genauer, wenn man in
tsconfigdeclarationMap: truehinzufügt.Ich bevorzuge fast immer, bei cmd+click den Quellcode zu sehen.