Import Export Typescript Angular

Wie das Typescript Upgrade auf ECMA2020 vorgreift

Die neuste Version von TypeScript steht bereit und überzeugt mit spannenden Neuerungen im Import und Export. Programmieren war noch nie so einfach!

Mitte Januar stellte Microsoft die Beta-Version 3.8 von TypeScript zum Testen für uns bereit – jetzt wurde das finale Update veröffentlicht. Version 3.8 besticht mit einer neuen und nützlichen Syntax für den Import und Export von Typen, sowie mit spannenden Features aus ECMAScript 2020.
TypeScript ist bekanntermaßen das Erfolgsrezept für die JavaScript-basierte Webentwicklung. Angular setzt bereits seit seinen Anfängen auf die typisierte JavaScript-Obermenge. Es wundert also nicht, dass Angular bereits mit Version 3.8 läuft. Inzwischen tun es ihm viele Webprojekte gleich und steigen auf TypeScript um. Nicht ungewöhnlich angesichts der Vorzüge, die Typescript gegenüber purem JavaScript mit sich bringt. Fehler werden durch die statische Typisierung bereits zur Compiler-Zeit aufgezeigt, und durch die Typinformationen schreibt sich der Code wie vom selbst.

TypeScripts Syntax

Typescript Angular Code


Die Syntax wie auch die Semantik von Typescript stützen sich so stark auf JavaScript, dass die Herausforderung für Entwickler, die von JavaScript zu TypeScript wechseln, vernachlässigbar wirkt. Wer auf TypeScript umsteigt, kann bereits geschriebenen JavaScript-Code und nahezu alle Frameworks und Libraries aus dem JavaScript-Ökosystem weiter nutzen. Ebenfalls kann TypeScript-Code über JavaScript aufgerufen werden. Der TypeScript wird dann letztendlich zu JavaScript-Code kompiliert, der in allen Browsern, in Node.js und in jeder JavaScript-Engine läuft, wenn diese ECMAScript ab Version 3 unterstützen.
Welche spannenden Features bringt nun die neuste Version 3.8 mit sich?

Microsoft entwickelt Typescript für uns alle sichtbar auf Github weiter. Dort findet sich auch die Raodmap des Microsoft-Teams sowie Ideen und Denkanstöße, die mit hoher Wahrscheinlichkeit die zukünftigen Features der Programmiersprache inspirieren werden.

Typescript Version 3.8 birgt eine neue Syntax für den Import und Export, um den Benutzern eine besser Handhabung für Import und Elision zu ermöglichen, sowie neue Features aus ECMAScript 2020.

Um auf Typen Bezug zu nehmen hat sich TypeScript bislang seiner Anlehnung an JavaScripts Import-Syntax bedient. So konnte man JavaScript-Values zusammen mit TypeScript-Typen importieren.
Die Funktion war zwar praktisch,  weil es meistens semi- relevant ist, ob ein Type oder Value importiert wird, sondern dass überhaupt etwas importiert wird.  Problematisch wurde es allerdings, wenn es wichtig war zu unterscheiden, was importiert wird. Das rührt daher, dass die Funktion zum Importieren von Elisionen, bei der TypeScript-Type-Importe weggelassen werden, wenn TypeScript JavaScript-Dateien angefordert werden.

// ./foo.ts
interface Options {
    // ...
}
export function doThing(options: Options) {
    // ...
}
// ./bar.ts
import { doThing, Options } from "./foo.js";

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

Quelle: devblogs.microsoft.com/typescript/announcing-typescript-3-8

TypeScripts Import Elision löschte Import Statements, deren Importe nur als Types genutzt werden. Bei Modulen mit Side-Effects kam es dabei zu Nebenwirkungen – um Side Effects sicherzustellen, war es deshalb bisher notwendig ein weiteres Import Statement zu setzen. In Angular vergangenen Versionen kam diese Problematik regelmäßig auf, so dass Services global registriert werden mussten, obwohl diese eigentlich nur der Types wegen importiert wurden und es gelegentlich zu App-Crashs kam.
TypeScript Version 3.8 hat für derartige Probleme die finale Lösung:
Das neueste TypeScript-Upgrade konzentriert sich auf type-only Importe und -Exporte sowie auf die Einhaltung der ECMAScript-Standards.

Import & Export


Mit der Absicht, dem Benutzer eine ideale Kontrolle über Import und Elision zu verschaffen, werden nun über import type nur Deklarationen, die explizit für Type-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 stellt nur einen Export bereit, der für Typkontexte verwendet wird und wird beim Kompilieren auch aus dem Output entfernt.

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

Quelle: devblogs.microsoft.com/typescript/announcing-typescript-3-8

importsNotUsedAsValues – Die neue Compiler-Flag

TypeScript 3.8 fügt zudem ein Compiler-Flag hinzu, die der Kontrolle von Importen dient, die zur Laufzeit nicht verwendet werden:
Die Flag heißt importsNotUsedAsValues und nimmt die Werte remove, preserve und error an.

removeist der aktuelle Default und wird die Standardeinstellung bleiben – Importe, die nicht verwendet werden, werden gedroppt.
preservebewirkt den Erhalt aller Importe, deren Values nicht verwendet werden. Dies kann dazu führen, dass auch importierte side-effects erhalten bleiben, wo Services nur wegen des Typs registriert werden
errorbewirkt ebenso den Erhalt aller Importe. Im Fall des Imports eines Values, der nur als Type verwendet wird, wird diese Flag eine Fehlermeldung werfen.

Mehr Informationen hierzu sind im Pull-Request zu finden, sowie zu den relevanten Änderungen zur Erweiterung wo Importe aus import type Deklerationen verwendet werden können.

ECMAScript Public…

Im Bezug auf den ECMAScript-Standard für JavaScript bietet TypeScript 3.8 Unterstützung für die Private Fields des ECMAScript Stage-3 Class Fields Proposals und deren Dekleration.
Public und private Fields werden demnach in ein einziges orthogonales Ganzes integriert. Private Fields werden mit einem vorangestellten # versehen. Sie werden auch private names genannt, und sind eindeutig der enthaltenden Klasse zugeordnet. Dieses sogenannte hard privacy bedeutet, dass sie ausschließlich innerhalb dieser gültig sind. Außerhalb des Klassen-Scope kann auf Private Fields weder zugegriffen werden, noch werden sie erkannt. Herkömmliche Property-Deklarationen prallen oft mit Klassennamen von irgendwelchen Unterklassen aufeinander und führen zu unnötigen Problemen. Dafür ist Private Fields die Lösung, denn jeder Field-name betrifft nur die Klasse, in der er enthalten ist:

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

Quelle: devblogs.microsoft.com/typescript/announcing-typescript-3-8/

..und Private Fields

Spezifische Accessibility Modifikatoren von TypeScript wie public  oder  private können in Private Fields nicht verwendt werden.
Vor allem für pure JavaScript-Dateien muss hinsichtlich des neuen Features eines berücksichtigt werden. Private Flieds müssen bestimmt werden, bevor sie einer Einheit zugewiesen werden. Das ist in sofern relevant, da es in JavaScript bislang möglich war, auf nicht deklarierte Properties zuzugreifen.

Dem Einsatzweck nach ist zu enscheiden, ob es besser ist, den TypeScripts Private Modifiers oder die neuen # private fields aus ECMAScript zu nutzen. Zu beachten ist hierbei , dass TypeScripts private Modifiers komplett gelöscht werden, wenn sie auf Properties angewendet werden. Die Daten sind zwar nicht weg, im kompilierten JavaScript-Output sind allerdings keine Daten dazu, wie die Property deklariert wurde. Während der Laufzeit verhält sie sich wie eine gewöhnliche Property. Privacy ist nur im Laufe der Kompilierzeit gesichert, was Clients einen Workaround darlegt, wenn beispielsweise der fehlenden Zugriff auf eine API zwischenzeitlich ausgeglichen werden soll. Sie funktioniert in jeder Laufzeitumgebung.


Auf ECMAScrips #privates kann konträr dazu, wie schon angeführt, außerhalb der für definierten Klasse nicht zugegriffen werden. Das ist je nach Intention ein Vorteil. Diese strenge Privacy ist die optimale Sicherheit, dass kein Zugriff auf Internals in eurem Code besteht.
Was #private den TypeScripts Private Modifiers voraus hat, ist dass TypeScript das Feature bisher nur bei ES6+ Targets greift. Das private-Keyword funktioniert mit allen Targets ab ES3.

Export * as ns -Syntax

Bislang haben wir alle Module mit ihren Komponenten einzeln exportiert. Dies konnte schon mal Zeit und einige Zeilen Code kosten:

export { Cat } from './Cat';
export { Alert, AlertText } from './Alert';
export { Petspace } from './Petspace';
export { Kingkong } from './Kingkong';
export { Bigbox } from './Bigbox';
export { Cartoon } from './Cartoon';
export { CakeRecipe, CakeRecipeItem } from './CakeRecipe';

Dafür hat ECMAScript 2020 noch eine Neuerung für uns im Petto. Hierzu wurde in TypeScript 3.8 eine neue Syntax übernommen, mit der alle in einem Modul verwendeten Komponenten in einer Zeile exportiert werden können. Damit sparen wir Zeit, Nerven und Geld.. was ja meist auf das Gleiche hinausläuft.

import * as stuff from "./stuff.js"
export { stuff }

So bleibt es letztendlich nun bei der einzigen Export-Zeile:
export * as stuff from "./stuff.js";

„Fast and loose“ incremental type-checking

TypeScript beinhaltet den Modus, --watch und den Modus--incremental, über welche TypeScript Dateien, wie auch deren Effekt auf andere Dateien trackt und Information im Speicher so weit wie möglich wiederverwendet.
Der Name der neuen Compiler-Option aus dem 3.8-Upgrade namens  OnlyAffectDirectDependencies verrät uns schon, dass nun nur explizit die Dateien gecheckt werden, die in einen Vorgang involviert sind. Mit dieser Option kann die Erstellungszeiten in bestimmten Dateien verkürzen werden, da TypeScript nur geänderte Dateien sowie Dateien, die sie direkt importieren, erneut überprüft / neu erstellt.
Dieses Feature empfiehlt sich eher für große Codebases, bei denen Entwickler bereit sind, komplette Projektfehler auf einen späteren Zeitpunkt zu verschieben. Wer also nach dem „Get it done – don’t get it perfekt!“- oder „move fast & fix things later“-Prinzip arbeitet, sollte sich das „Fast and loose“ incremental type-checking genauer ansehen.

Top-Level await

Weitere Unterstützung beim Programmieren bringt uns die praktische, bevorstehende ECMAScript-Funktion namens Top-Level-await.
Umgebungen mit Input und Output in JavaScript sind meistens asynchron. Die meisten APIs geben Promises zurück, so dass vorteilhafterweise Vorgänge parallel ausgeführt werden können. Beim Laden externer Inhalte ist diese Asynchronität allerdings nicht gewünscht.
JavaScript-Entwickler definieren häufig eine asynchrone Funktion, um await zu verwenden, und rufen die Funktion nach dem Definieren direkt auf. Zuvor war es nämlich in JavaScript (wie auch in anderen Sprachen mit ähnlicher Funktion) nur zulässig await nur innerhalb einer asynchronen Funktion aufzurufen:

async function main(){
     const response = await fetch("..."); 
     const greeting = await response.text();
     console.log(greeting);
     }
main()
    .catch(e => console.error(e))

Quelle: typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#top-level-await

Mit dem neuen Top-Level-await-Feature aus ECMAScript 2020 ist es in TypeScript 3.8 nun möglich, await auf dem obersten Level eines Moduls zu nutzen. Einer async-Funktion bedarf es dafür nicht mehr.

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};

Quelle: typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#top-level-await

Top Level await funktioniert aber nur auf dem obersten Level eines Moduls. Dateien gelten nur dann als Module, wenn Typescript einen import oder export findet. Um das sicherzustellen, sollte export {} wenn nötig als Boilerplate auftauchen.
Im Moment funktioniert Top-Level await nur für Target Compiler Options ES17+.
Weitere Informationen dazu findet ihr hier.

JSDoc Property Modifiers

Über die neue Flag namens allowJS ist es nun möglich in TypeScript 3.8 JavaScript-Dateien zu nutzen. Über die checkJS-Option kann eine Typüberprüfung gemacht werden. Alternativ könnt ihr euren JavaScript-Dateien auch // @ts-check voranstellen, da JavaScript keine eigene Syntax für die Typüberprüfung hat. Die Typüberprüfung in JavaScript-Dateien funktioniert so, dass TypeScript 3.8 Anleihen bei JSDoc macht. Es versteht die Accessibility-Modifier @public@private und @protected, die publicprivate und protected in TypeScript entsprechen.
Der neue @readonly-Modifier sorgt dafür, dass einer Property nur bei der Initialisierung ein Wert zugewiesen werden kann.

Die neuen watchOptions

Für die Überwachung von Directories hat TypeScript 3.8 auch eine neue Strategie parat, über die wir Veränderungen von Node-Modulen besser unter Kontrolle haben. Für die individuelle und flexible Anpassung an die Ansprüche unserer jeweiligen Projekte, wurde mit TypeScript 3.8 ein watchOptions-Field in den tsconfig.json / jsconfig.json-Dateien eingeführt. Auch hierfür findet ihr mehr Informationen im Microsoft-Blog oder auf den Pull-Request auf GitHub .

TypeScript 3.8 könnt ihr euch über NuGet oder über NPM installieren:
npm install typescript

1 Kommentar zu „Wie das Typescript Upgrade auf ECMA2020 vorgreift“

  1. Pingback: Wird Deno Land 1.0, Node.js von Thron stoßen? - ITGY

Kommentar verfassen