Warum kann Typescript das kompilieren?

Hendoul

Commander
Registriert
Apr. 2008
Beiträge
2.156
Hi :)

Ich bin dabei die target Version in einem Projekt anzuheben. Aus Testzwecken wollte ich dann mal ausprobieren was passiert, wenn ich ein JS-Feature nutze, dass erst in einer späteren ES Version dazugekommen ist als das was ich im target konfiguriert habe

Kleiner Ausschnitt aus meiner tsconfig
JSON:
"compilerOptions": {
        "target": "ES2015",
        "module": "ES2022",
        "moduleResolution": "node",
        "baseUrl": "../abc/src/main/webpack",
        "removeComments": true,
        "allowJs": true,
        "preserveConstEnums": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,


Testcode:
Javascript:
'str'.isWellFormed();

const entries = Object.entries({a: 1});

const b = [1, 2, 3].includes(3);

isWellFormed() ist ES2024
Object.entries ist ES2017
includes() ist ES2016

Aber nur bei isWellFormed() schlägt die Kompilierung fehl mit der Meldung:
TS2550: Property 'isWellFormed' does not exist on type '"str"'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2024' or later.

Die anderen 2 sind kein Problem. Aber warum? Die müssten doch auch fehlschlagen?

ChatGPT meint:
Array.prototype.includes wurde in ECMAScript 2016 (ES7) eingeführt. Die Typdefinitionen für diese Methode sind jedoch in der Standardbibliothek von TypeScript enthalten, die auch für frühere Zielversionen verwendet wird. Das bedeutet, dass der TypeScript-Compiler keine Fehler meldet, wenn includes verwendet wird, selbst wenn target auf ES2015 gesetzt ist.

Wenn das stimmt, dann verstehe ich das mit dem target nicht wirklich.

Wenn ich den Testcode auf TS eingebe, werden alle 3 Methoden mit einem error versehen:
https://www.typescriptlang.org/play/

Was fehlt in meinem Projekt, dass auch die anderen 2 Methoden fehlschlagen beim compilieren?

Ist hier evtl. IntelliJ das Problem? Ich verwende die Version 2023.3.1
 
Zuletzt bearbeitet:
Weil das Target erstmal nur angibt, nach was der Kompiler den TS-Code übersetzen soll. Da ersetzt der dann in dem Standard nicht existierende Features mit passendem Ersatzcode, der die Funktion nachbildet.

Dass 2 der 3 Dinge keinen Fehler erzeugen, dürfte dann daran liegen, dass die von der "module" Version abgedeckt werden. Der Kompiler geht also davon aus, dass dein Code ES2022 ist und behandelt den so. Dabei versucht er es dann, wie oben erwähnt, in ES2017 zu überführen.

Dass .isWellFormed() dagegen ein Fehler erzeugt, liegt dann daran, dass der Kompiler von ES2022 Code ausgeht, wo es die Funktion eben nicht gibt.
 
module hat meines Wissens nach nur mit den import/export/require Syntax zu tun. Ist also hier nicht relevant.
Es funktioniert ja auf https://www.typescriptlang.org/play/ wenn ich dort ES2016 und module ES2022 angebe, es werden alle 3 Methoden reklamiert. Nur bei mir in IntelliJ scheint das nicht zu funktionieren.

Und so wie ich das verstanden habe macht der TS-compiler auch kein transpile für Methoden die er nicht kennt, dafür müsste man babel nutzen. Was er kann ist syntax sugar umwandeln, also z.B. fat-arrow. Aber die Methode include() kann er nicht transpilieren/polyfillen.

Ich kann auch "module": "ES2015" verwenden, die Methoden werden trotzdem nicht als error markiert und ich kann diese compilen.
 
Zuletzt bearbeitet:
Mal ganz blöd gefragt: Bist du sicher, dass du in der richtigen tsconfig.json Datei guckst? Könntest die Datei sonst mal ungültig machen und schauen ob er dann immer noch kompiliert. Sonst nutzt er ggf. eine Standardkonfiguration.

Alternativ mal das log level vom Typescript Compiler erhöhen und schauen mit welchen Optionen er kompiliert
 
Kein Problem, manchmal ist es ja wirklich irgendwas kleines oder banales das man übersieht. Aber ja es ist die richtige, denn wenn ich ES2024 reinschreibe, dann wird 'str'.isWellFormed(); gültig.

Das mit dem Log-Level werde ich mal ausprobieren, danke :)

Das Loggen fördert auch nicht viel mehr Information zutage:
JSON:
options: {
    logLevel: 'info',
        logInfoToStdOut: true,
            compilerOptions: {
                diagnostics: true,
            },
}

gibt noch folgendes aus:
ts-loader: Using typescript@5.8.2 and C:\Project\xyz\tsconfig.json
Was korrekt ist
 
Zuletzt bearbeitet:
Ich kann das reproduzieren. Ich glaube das passiert, wenn du "@types/node" als Dependency in packages.json drin hast. In "node_modules/@types/node/index.d.ts" findet sich folgende Zeile:

Code:
// Reference required TypeScript libs:
/// <reference lib="es2020" />

Dadurch wird also das Sprachlevel auf es2020 hochgesetzt.
 
  • Gefällt mir
Reaktionen: Physikbuddha, n/a und marcOcram
Das ist es tatsächlich, vielen Dank!
 
Ich würde die beiden Werte von target und module mal vertauschen. Dann sollten alle drei Anweisungen deines Codes nicht mehr kompilieren.

Generell sollte man die module version so klein wie möglich und die target version so groß wie im eigenen Code gebraucht wählen.

Beispiel:

Du möchtest auf isWellFormed() verzichten, alles Andere soll aber noch kompilieren. Dann wählst du

Code:
        "target": "ES2017",
        "module": "ES2020",

Dadurch sollte nur isWellFormed() fehlschlagen
 
Warum sollte man die module Version so klein wie möglich halten?
 
Nein das möchte ich explizit nicht, die letzten 2 Versionen von Chrome, Edge, Firefox und Safari unterstützen so gut wie alle ES2024 Standards. Was nicht unterstützt wird unterbinde ich mit dem eslint-plugin-es-x
 
Nutzt du keinen Transpiler? Ist doch völlig unerheblich, was die Browser unterstützen, so lange das Transpile-Target passt.
 
Nein, Babel macht ja nur Sinn, wenn ich Browser-Versionen unterstützen möchte die gewisse Features/Syntax nicht unterstützen. Da ich aber nur die aktuellen 2 Versionen von den grossen muss (Firefox, Chrome, Edge, Safari) hat sich Babel mittlerweile erübrigt. Ich bin froh wenn ich auf Babel verzichten kann.
 
Du musst ja so und so transpilieren, da TS nicht nativ unterstützt wird. Gleiches gilt für viele ES2024 features.
esbuild braucht ja keinen separaten Transpiler wie Babel mehr, so lange man auf ES5 Support verzichten kann.
 
Zurück
Oben