News

Vorgriff auf ECMAScript 2020: Das sind die spannendsten neuen Features in TypeScript 3.8

TypeScript-Code. (Bild via Instacode)

Seit Mitte Januar ist die Beta von Version 3.8 der von Microsoft entwickelten Programmiersprache TypeScript zum Testen verfügbar – jetzt wurde das finale Update veröffentlicht. Version 3.8 kommt mit neuen Features aus ECMAScript 2020 sowie einer neuen Syntax für den Im- und Export von Typen.  

TypeScript basiert auf Vorschlägen zum ES6-Standard. Viele Konzepte der Sprache wie Klassen, Vererbung oder Module sind daher deckungsgleich mit ES6. Syntax und Semantik der Sprache sind stark an JavaScript angelehnt. Die Lernkurve ist für Entwickler, die von JavaScript zu TypeScript wechseln, relativ moderat. Wer mit TypeScript arbeitet, kann dabei bereits existenten JavaScript-Code und die meisten Frameworks und Libraries aus dem JavaScript-Ökosystem nutzen. TypeScript-Code kann über JavaScript aufgerufen werden. Am Ende wird TypeScript zu JavaScript-Code kompiliert, der in allen Browsern, in Node.js und in jeder JavaScript-Engine läuft, die ECMAScript ab Version 3 unterstützt. Version 3.8 von TypeScript kommt mit einigen Neuerungen.

Type-only Im- und Exporte

Für das Referenzieren von Typen macht TypeScript Anleihen bei JavaScripts Import-Syntax. So war es bisher möglich, JavaScript-Values zusammen mit TypeScript-Typen zu importieren, etwa so:

Nix mehr verpassen: Die t3n Newsletter zu deinen Lieblingsthemen! Jetzt anmelden
// ./foo.ts
interface Options {
// ...
}
export function doThing(options: Options) {
//
}

// ./bar.ts
import { doThing, Options } from "./foo.js";
// doThing is a JS value, Options is purely a TypeScript type

function doThingBetter(options: Options) {
// do something twice as good
doThing(options);
doThing(options);
}

*Alle Code-Snippets wurden, soweit nicht anders gekennzeichnet, aus Michael Rosenwassers Blogpost für den Microsoft-Blog übernommen.

Das ist bequem, weil es meistens weniger eine Rolle spielt, ob ein Type oder Value importiert wird. Wichtig ist, überhaupt etwas zu importieren. In manchen Fällen ist es aber wichtig, zu unterscheiden, was importiert wird. TypeScripts Import Elision löscht Import Statements, deren Importe nur als Types genutzt werden. Das führt etwa bei Modulen mit Side-Effects zu abweichendem Verhalten – um Side Effects sicherzustellen, war bisher ein zweites Import Statement nötig.

Dieses Problem kam zum Beispiel in Angular in Version 1.x regelmäßig auf, wo Services global registriert werden mussten, diese aber überhaupt nur wegen der Types importiert wurden.

// ./service.ts
export class Service
{    // ...}
register("globalServiceId", Service);

// ./consumer.ts
import { Service } from "./service.js";
inject("globalServiceId", function (service: Service) {
// do stuff with Service
});

Im Beispiel wird ./service.js aufgrund diesen Verhaltens nie ausgeführt. Die Folge: Während der Laufzeit crasht die App.

Um derartige Probleme zu vermeiden, wurde in Version 3.8 eine Syntax für Type-only Im- und Exporte eingeführt. So sieht sie aus:

import type { SomeThing } from "./some-module.js";
export type { SomeThing };

Über import type werden nur Deklarationen, die ausschließlich für Typen-Annotationen und Deklarationen genutzt werden, importiert. Ein solches Statement wird beim Kompilieren immer komplett gelöscht, sodass während der Laufzeit nichts mehr davon im Code vorhanden ist.

export type kann nur für type-Kontexte genutzt werden und wird beim Kompilieren ebenfalls aus dem Output gelöscht.

Neue Compiler-Flag

In Version 3.8 wurde außerdem eine Compiler Flag hinzugefügt, über die ihr kontrollieren könnt, was aus Imports wird, die zur Laufzeit nicht verwendet werden. importsNotUsedAsValues heißt sie. Die Flag nimmt drei verschiedene Werte an:

remove: ist derzeit der Default und wird der Default bleiben – Importe, die nicht verwendet werden, werden gedroppt.

preserve: führt zum Erhalt aller Importe, deren Values nicht verwendet werden. So können zum Beispiel side effects, wo Services nur wegen des Typs registriert werden, erhalten bleiben.

error: Wie die preserve-Flag erhält die error-Flag alle Importe. Im Fall des Imports eines Values, der nur als Type verwendet wird, bekommt ihr mit dieser Flag allerdings eine Fehlermeldung. Das ist zum Beispiel nützlich, um sicherzustellen, dass ihr Values nicht aus Versehen importiert, Importe von Nebeneffekten aber trotzdem explizit machen wollt.

ECMAScript Private Fields

TypeScript 3.8 unterstützt die Private Fields des ECMAScript Stage-3 Class Fields Proposals. Private Fields schreibt ihr mit einem vorangestellten #. Sie werden auch private names genannt.

class Person {
#name: string
constructor(name: string){
this.#name = name;
} greet() {
console.log(`Hello, my name is ${this.#name}!`);    }}

let jeremy = new Person("Jeremy Bearimy"); jeremy.#name
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.

Private Fields sind ausschließlich innerhalb der Klasse gültig, in der sie enthalten sind.

TypeScript-eigene Accessibility-Modifiers wie public oder private könnt ihr in Private Fields nicht verwenden. Und: Außerhalb der Klasse, in der sie enthalten sind, kann auf Private Fields weder zugegriffen noch können sie entdeckt werden. Das wird auch Hard Privacy genannt. Reguläre Property-Deklarationen kollidieren oft mit Klassennamen von irgendwelchen Unterklassen, mit Private Fields passiert das nicht – jeder Field Name betrifft nur die Klasse, in der er enthalten ist.

Wer das neue Feature in reinen JavaScript-Dateien nutzt: Diese müssen immer bestimmt werden, bevor sie einer Entität zugewiesen werden. In JavaScript war es bisher erlaubt, auf nicht deklarierte Properties zuzugreifen. Mit Private Fields ist das nicht möglich.

class C {
/** @type {number} */
#foo;
constructor(foo: number) {
// This works.
this.#foo = foo;
}
}

Ob ihr TypeScripts Private Modifiers nutzt oder die neuen # private fields aus ECMAScript, hängt vom jeweiligen Einsatzweck ab. TypeScripts private Modifiers werden, wenn sie auf Properties angewendet werden, komplett gelöscht. Die Daten sind zwar da, im kompilierten JavaScript-Output sind aber keine Informationen darüber, wie die Property deklariert wurde, hinterlegt – während der Laufzeit verhält sie sich wie eine normale Property. Das heißt, Privacy ist nur während der Kompilierzeit sichergestellt.

Diese „softe“ Privacy bietet Clients einen Workaround, zeitweise fehlenden Zugriff auf eine API auszugleichen. Und sie funktioniert in jeder Laufzeitumgebung. Auf ECMAScrips #privates kann im Gegensatz dazu außerhalb der Klasse, in der sie definiert wurden, nicht zugegriffen werden. Deren strikte Privacy ist hilfreich, wenn ihr wirklich sicherstellen wollt, dass niemand auf Internals in eurem Code zugreift. Außerdem macht das Feature – wie bereits erwähnt – Sub-Classing einfacher, Kollisionen von Field-Benennungen sind damit ausgeschlossen – anders bei TypeScripts private-Keyword.

Allerdings unterstützt TypeScript das Feature bisher nur bei ES6+ Targets. Im Gegensatz dazu funktioniert das private-Keyword mit allen Targets ab ES3.

Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Schreib den ersten Kommentar!

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!

Hey du! Schön, dass du hier bist. 😊

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team bestehend aus 65 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Danke für deine Unterstützung.

Digitales High Five,
Stephan Dörner (Chefredakteur t3n.de) & das gesamte t3n-Team

Anleitung zur Deaktivierung