You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Inspiriert von [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript).
5
5
6
6
## Inhalt <!-- omit in toc -->
@@ -22,7 +22,7 @@ Inspiriert von [clean-code-javascript](https://github.com/ryanmcdermott/clean-co
22
22
23
23

24
24
25
-
Software-Entwicklungs-Prinzipien, aus Robert C. Martins Buch [_Clean Code_](https://amzn.to/33HgLXZ) (* affiliate link), angepasst für TypeScript. Dies ist kein Style Guide. Es ist ein Leitfaden zur Erstellung von [lesbarer, wiederverwendbarer und refaktorierbarer](https://github.com/ryanmcdermott/3rs-of-software-architecture) Software in TypeScript.
25
+
Software-Entwicklungs-Prinzipien, aus Robert C. Martins Buch [_Clean Code_](https://amzn.to/33HgLXZ) (\* affiliate link), angepasst für TypeScript. Dies ist kein Style Guide. Es ist ein Leitfaden zur Erstellung von [lesbarer, wiederverwendbarer und refaktorierbarer](https://github.com/ryanmcdermott/3rs-of-software-architecture) Software in TypeScript.
26
26
27
27
Nicht jedes Prinzip hierin muss strikt befolgt werden, und noch weniger werden sie allgemein anerkannt sein. Dies hier sind Richtlinien und nichts weiter. Aber sie sind solche, die über viele Jahre kollektiver Erfahrung von den Autoren von _Clean Code_.
@@ -148,7 +148,7 @@ for (const [id, user] of users) {
148
148
149
149
### Vermeide Mental Mapping
150
150
151
-
Explizit ist besser als implizit.
151
+
Explizit ist besser als implizit.
152
152
_Klarheit ist der König._
153
153
154
154
**Schlecht:**
@@ -626,6 +626,25 @@ function createMenu(config: MenuConfig) {
626
626
createMenu({ body: "Bar" });
627
627
```
628
628
629
+
Oder du kannst den Spread-Operator verwenden:
630
+
631
+
```ts
632
+
function createMenu(config:MenuConfig) {
633
+
const menuConfig = {
634
+
title: "Foo",
635
+
body: "Bar",
636
+
buttonText: "Baz",
637
+
cancellable: true,
638
+
...config,
639
+
};
640
+
641
+
// ...
642
+
}
643
+
```
644
+
645
+
Der Spread-Operator und `Object.assign()` sind sich sehr ähnlich.
646
+
Der Hauptunterschied besteht darin, dass "Spreading" neue Eigenschaften definiert, während `Object.assign()` sie festlegt. Ausführlicher wird der Unterschied in [diesem Thread erklärt](https://stackoverflow.com/questions/32925460/object-spread-vs-object-assign).
647
+
629
648
Alternativ kannst du auch eine Destrukturierung mit Standardwerten verwenden:
630
649
631
650
```ts
@@ -723,16 +742,18 @@ console.log(name);
723
742
724
743
### Vermeide Nebenwirkungen (Teil 2)
725
744
726
-
In JavaScript werden Primitive als Wert und Objekte/Arrays als Referenz übergeben. Im Fall von Objekten und Arrays, wenn deine Funktion eine Änderung in einem Warenkorb-Array vornimmt, z.B. indem du einen Artikel zum Kauf hinzufügst, dann wird jede andere Funktion, die dieses `cart`-Array benutzt, von dieser Hinzufügung betroffen sein. Das kann großartig sein, es kann aber auch schlecht sein. Lass uns eine schlechte Situation vorstellen:
745
+
Browser und Node.js verarbeiten nur JavaScript, daher muss jeder TypeScript-Code vor dem Ausführen oder Debuggen kompiliert werden. In JavaScript sind einige Werte unveränderlich (immutable) und andere veränderbar (mutable). Objekte und Arrays sind zwei Arten von veränderbaren Werten, daher ist es wichtig, sie sorgfältig zu behandeln, wenn sie als Parameter an eine Funktion übergeben werden. Eine JavaScript-Funktion kann die Eigenschaften eines Objekts oder den Inhalt eines Arrays ändern, was leicht zu Fehlern an anderer Stelle führen kann.
746
+
747
+
Nehmen wir an, es gibt eine Funktion, die einen Array-Parameter akzeptiert, der einen Warenkorb darstellt. Wenn die Funktion eine Änderung in diesem Warenkorb-Array vornimmt - z. B. indem sie einen Artikel zum Kauf hinzufügt -, dann wird jede andere Funktion, die dasselbe Warenkorb-Array verwendet, von dieser Änderung betroffen sein. Das mag toll sein, kann aber auch schlecht sein. Stellen wir uns eine schlechte Situation vor:
727
748
728
-
Der Benutzer klickt auf den "Purchase" Button, der eine `purchase` Funktion aufruft, die eine Netzwerkanfrage erzeugt und das `cart` Array an den Server sendet. Aufgrund einer schlechten Netzwerkverbindung muss die Kauffunktion die Anfrage immer wieder neu versuchen. Nun, was ist, wenn der Benutzer in der Zwischenzeit versehentlich auf den "In den Warenkorb"-Button eines Artikels klickt, den er eigentlich nicht will, bevor die Netzwerkanfrage beginnt? Wenn das passiert und die Netzwerkanforderung beginnt, dann wird die Kauffunktion den versehentlich hinzugefügten Artikel senden, weil sie eine Referenz auf ein Warenkorb-Array hat, das die Funktion `addItemToCart` durch das Hinzufügen eines unerwünschten Artikels verändert hat.
749
+
Der Benutzer klickt auf den "Purchase" Button, der eine `purchase` Funktion aufruft, die eine Netzwerkanfrage stellt und das `cart` Array an den Server sendet. Aufgrund einer schlechten Netzwerkverbindung muss die Funktion `purchase`die Anfrage immer wieder neu versuchen. Was passiert, wenn der Nutzer in der Zwischenzeit versehentlich auf einen Artikel klickt, den er eigentlich gar nicht haben will, bevor die Netzwerkanfrage gestartet wird? Wenn das passiert und die Netzwerkanfrage beginnt, sendet die `purchase` Funktion den versehentlich hinzugefügten Artikel, weil das Array `cart` geändert wurde.
729
750
730
-
Eine gute Lösung wäre, dass die Funktion `addItemToCart` immer den `Cart` klont, ihn bearbeitet und den Klon zurückgibt. Dies stellt sicher, dass keine anderen Funktionen, die eine Referenz auf den Warenkorb haben, von den Änderungen betroffen sind.
751
+
Eine gute Lösung wäre, wenn die Funktion `addItemToCart` immer `cart` klont, ihn bearbeiten und den Klon zurückgeben würde. Das würde sicherstellen, dass Funktionen, die noch den alten Warenkorb verwenden, nicht von den Änderungen betroffen sind.
731
752
732
753
Zwei Vorbehalte sind bei diesem Ansatz zu erwähnen:
733
754
734
755
1. Es kann Fälle geben, in denen du das Eingabeobjekt tatsächlich ändern möchtest, aber wenn du diese Programmierpraxis anwendest, wirst du feststellen, dass diese Fälle ziemlich selten sind. Die meisten Dinge können so refaktorisiert werden, dass sie keine Seiteneffekte haben! (siehe [pure function](https://en.wikipedia.org/wiki/Pure_function))
735
-
2. Das Klonen von großen Objekten kann sehr teuer in Bezug auf die Performance sein. Glücklicherweise ist dies in der Praxis kein großes Problem, da es großartige Bibliotheken gibt, die es ermöglichen, dass diese Art von Programmieransatz schnell und nicht so speicherintensiv ist, wie es für dich wäre, wenn du Objekte und Arrays manuell klonen würdest.
756
+
2. Das Klonen von großen Objekten kann sehr teuer in Bezug auf die Performance sein. Glücklicherweise ist dies in der Praxis kein großes Problem, da es [großartige Bibliotheken](https://facebook.github.io/immutable-js/) gibt, die es ermöglichen, dass diese Art von Programmieransatz schnell und nicht so speicherintensiv ist, wie es für dich wäre, wenn du Objekte und Arrays manuell klonen würdest.
Verwende Generatoren und Iterables, wenn du mit Sammlungen von Daten arbeitest, die wie ein Stream verwendet werden.
1076
+
Verwende Generatoren und Iterables, wenn du mit Sammlungen von Daten arbeitest, die wie ein Stream verwendet werden.
1056
1077
Dafür gibt es einige gute Gründe:
1057
1078
1058
1079
- entkoppelt den Aufrufer von der Generatorimplementierung in dem Sinne, dass der Aufrufer entscheidet, auf wie viele Items er zugreift
@@ -1238,7 +1259,7 @@ class Circle {
1238
1259
1239
1260
### Bevorzuge Unveränderbarkeit
1240
1261
1241
-
TypeScripts Typsystem erlaubt es dir, einzelne Eigenschaften auf einer Schnittstelle/Klasse als _readonly_ zu markieren. Dies erlaubt es dir, auf funktionale Weise zu arbeiten (eine unerwartete Mutation ist schlecht).
1262
+
TypeScripts Typsystem erlaubt es dir, einzelne Eigenschaften auf einer Schnittstelle/Klasse als _readonly_ zu markieren. Dies erlaubt es dir, auf funktionale Weise zu arbeiten (eine unerwartete Mutation ist schlecht).
1242
1263
Für fortgeschrittenere Szenarien gibt es einen eingebauten Typ `Readonly`, der einen Typ `T` nimmt und alle seine Eigenschaften als readonly markiert, indem er gemappte Typen verwendet (siehe [gemappte Typen](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types)).
Verwende `type`, wenn du eine Vereinigung oder Kreuzung brauchst. Verwende ein `Interface`, wenn du `extends` oder `implements` brauchst. Es gibt keine strikte Regel, verwende die, die für dich funktioniert.
1339
-
Für eine detailliertere Erklärung siehe diese [Antwort](<https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types/54101543#54101543>) über die Unterschiede zwischen `type` und `interface` in TypeScript.
1359
+
Verwende `type`, wenn du eine Vereinigung oder Kreuzung brauchst. Verwende ein `Interface`, wenn du `extends` oder `implements` brauchst. Es gibt keine strikte Regel, verwende die, die für dich funktioniert.
1360
+
Für eine detailliertere Erklärung siehe diese [Antwort](https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types/54101543#54101543) über die Unterschiede zwischen `type` und `interface` in TypeScript.
1340
1361
1341
1362
**Schlecht:**
1342
1363
@@ -2030,14 +2051,14 @@ DIP wird normalerweise durch die Verwendung eines Inversion of Control (IoC) Con
2030
2051
**Schlecht:**
2031
2052
2032
2053
```ts
2033
-
import { readFileasreadFileCb } from'fs';
2034
-
import { promisify } from'util';
2054
+
import { readFileasreadFileCb } from"fs";
2055
+
import { promisify } from"util";
2035
2056
2036
2057
const readFile =promisify(readFileCb);
2037
2058
2038
2059
typeReportData= {
2039
2060
// ..
2040
-
}
2061
+
};
2041
2062
2042
2063
classXmlFormatter {
2043
2064
parse<T>(content:string):T {
@@ -2046,33 +2067,32 @@ class XmlFormatter {
2046
2067
}
2047
2068
2048
2069
classReportReader {
2049
-
2050
2070
// BAD: We have created a dependency on a specific request implementation.
2051
2071
// We should just have ReportReader depend on a parse method: `parse`
2052
2072
privatereadonly formatter =newXmlFormatter();
2053
2073
2054
2074
async read(path:string):Promise<ReportData> {
2055
-
const text =awaitreadFile(path, 'UTF8');
2075
+
const text =awaitreadFile(path, "UTF8");
2056
2076
returnthis.formatter.parse<ReportData>(text);
2057
2077
}
2058
2078
}
2059
2079
2060
2080
// ...
2061
2081
const reader =newReportReader();
2062
-
const report =awaitreader.read('report.xml');
2082
+
const report =awaitreader.read("report.xml");
2063
2083
```
2064
2084
2065
2085
**Gut:**
2066
2086
2067
2087
```ts
2068
-
import { readFileasreadFileCb } from'fs';
2069
-
import { promisify } from'util';
2088
+
import { readFileasreadFileCb } from"fs";
2089
+
import { promisify } from"util";
2070
2090
2071
2091
const readFile =promisify(readFileCb);
2072
2092
2073
2093
typeReportData= {
2074
2094
// ..
2075
-
}
2095
+
};
2076
2096
2077
2097
interfaceFormatter {
2078
2098
parse<T>(content:string):T;
@@ -2084,30 +2104,28 @@ class XmlFormatter implements Formatter {
Callbacks sind nicht sauber und verursachen exzessive Mengen an Verschachtlungen _(die Callback-Hölle)_.
2247
+
Callbacks sind nicht sauber und verursachen exzessive Mengen an Verschachtlungen _(die Callback-Hölle)_.
2230
2248
Es gibt Hilfsprogramme, die bestehende Funktionen im Callback-Stil in eine Version umwandeln, die Versprechen zurückgibt (für Node.js siehe [`util.promisify`](https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original), für allgemeine Zwecke siehe [pify](https://www.npmjs.com/package/pify), [es6-promisify](https://www.npmjs.com/package/es6-promisify)).
2231
2249
2232
2250
**Schlecht:**
@@ -2362,8 +2380,8 @@ Ausgelöste Fehler sind eine gute Sache! Sie bedeuten, dass die Laufzeitumgebung
2362
2380
2363
2381
### Werfe immer Fehler
2364
2382
2365
-
Sowohl JavaScript als auch TypeScript erlauben es dir, ein beliebiges Objekt zu werfen. Ein Promise kann auch mit einem beliebigen Grundobjekt verworfen werden.
2366
-
Es ist ratsam, die `throw` Syntax mit einem `Error` Typ zu verwenden. Das liegt daran, dass dein Fehler in höherem Code mit einer `catch` Syntax abgefangen werden könnte. Es wäre sehr verwirrend, dort eine String-Meldung zu fangen und würde das [Debugging schmerzhafter machen](https://basarat.gitbook.io/typescript/type-system/exceptions#always-use-error).
2383
+
Sowohl JavaScript als auch TypeScript erlauben es dir, ein beliebiges Objekt zu werfen. Ein Promise kann auch mit einem beliebigen Grundobjekt verworfen werden.
2384
+
Es ist ratsam, die `throw` Syntax mit einem `Error` Typ zu verwenden. Das liegt daran, dass dein Fehler in höherem Code mit einer `catch` Syntax abgefangen werden könnte. Es wäre sehr verwirrend, dort eine String-Meldung zu fangen und würde das [Debugging schmerzhafter machen](https://basarat.gitbook.io/typescript/type-system/exceptions#always-use-error).
2367
2385
Aus dem gleichen Grund solltest du Promises mit `Error` Typen ablehnen.
2368
2386
2369
2387
**Schlecht:**
@@ -2397,7 +2415,7 @@ async function get(): Promise<Item[]> {
2397
2415
```
2398
2416
2399
2417
Der Vorteil der Verwendung von `Error` Typen ist, dass sie von der Syntax `try/catch/finally` unterstützt werden und implizit alle Fehler die Eigenschaft `stack` haben, was
2400
-
sehr mächtig für das Debugging ist.
2418
+
sehr mächtig für das Debugging ist.
2401
2419
Es gibt auch andere Alternativen, die `throw`-Syntax nicht zu verwenden und stattdessen immer eigene Fehlerobjekte zurückzugeben. TypeScript macht dies noch einfacher. Betrachte das folgende Beispiel:
2402
2420
2403
2421
```ts
@@ -2556,7 +2574,7 @@ type Container = {
2556
2574
};
2557
2575
```
2558
2576
2559
-
Verwende bevorzugt `PascalCase` für Klassen-, Interface-, Typ- und Namensraumnamen.
2577
+
Verwende bevorzugt `PascalCase` für Klassen-, Interface-, Typ- und Namensraumnamen.
2560
2578
Verwende bevorzugt `camelCase` für Variablen, Funktionen und Klassenmitglieder.
2561
2579
2562
2580
**[⬆ zum Anfang](#table-of-contents)**
@@ -2731,7 +2749,7 @@ import { UserService } from "@services/UserService";
2731
2749
2732
2750
Die Verwendung eines Kommentars ist ein Hinweis darauf, dass man sich ohne ihn nicht ausdrücken kann. Der Code sollte die einzige Quelle der Wahrheit sein.
2733
2751
2734
-
> Don’t comment bad code—rewrite it.
2752
+
> Don’t comment bad code—rewrite it.
2735
2753
> — _Brian W. Kernighan and P. J. Plaugher_
2736
2754
2737
2755
### Bevorzuge selbsterklärenden Code anstelle von Kommentaren
@@ -2813,7 +2831,7 @@ function combine(a: number, b: number): number {
2813
2831
2814
2832
### Vermeide Positionsmarkierungen
2815
2833
2816
-
Sie fügen normalerweise nur Lärm hinzu. Lass die Funktionen und Variablennamen zusammen mit der richtigen Einrückung und Formatierung deinem Code die visuelle Struktur geben.
2834
+
Sie fügen normalerweise nur Lärm hinzu. Lass die Funktionen und Variablennamen zusammen mit der richtigen Einrückung und Formatierung deinem Code die visuelle Struktur geben.
2817
2835
Die meisten IDEs unterstützen Code-Folding-Features, die es dir ermöglichen, Codeblöcke zu komprimieren/expandieren (siehe Visual Studio Code [folding regions](https://code.visualstudio.com/updates/v1_17#_folding-regions)).
2818
2836
2819
2837
**Schlecht:**
@@ -2917,5 +2935,7 @@ Diese Prinzipien sind auch in anderen Sprachen verfügbar:
Referenzen werden hinzugefügt, sobald die Übersetzungen abgeschlossen sind.
2921
-
Schau dir diese [Diskussion](https://github.com/labs42io/clean-code-typescript/issues/15) für weitere Details und Fortschritte an. Du kannst einen unverzichtbaren Beitrag zur _Clean Code_ Community leisten, indem du dies in deine Sprache übersetzst.
2938
+
Referenzen werden hinzugefügt, sobald die Übersetzungen abgeschlossen sind.
2939
+
Schau dir diese [Diskussion](https://github.com/labs42io/clean-code-typescript/issues/15) für weitere Details und Fortschritte an. Du kannst einen unverzichtbaren Beitrag zur _Clean Code_ Community leisten, indem du dies in deine Sprache übersetzt.
0 commit comments