
Working Draft· Folge 694
Revision 694: React- & TypeScript-Glücksrad, mit Hans-Christian Otto
Dienstag, 23. Dezember 2025 · 1 h 44
Kapitelklicken springt direkt hin
Shownotes
In dieser Revision drehen wir nochmal das Glücksrad – allerdings zum Themenbereich TypeScript und React. Gemeinsam mit unserem Gast Kiki (Hans-Christian Otto) (hans-christian-otto.de), seines Zeichens Paramount Leader von Suora (suora.com), picken wir zufällige React- und TypeScript-Themen und arbeiten uns von dort aus tief in Parallelwelten, Typsysteme, Debugging-Philosophie und die Grenzen statischer Analyse vor. Es geht um React DevTools, Web Components, any vs. unknown, TypeScript-Overloads, Decorators und die Frage, warum HTML kaputt sein darf – und vermutlich immer bleiben wird.
[] React useDebugValue (react.dev/reference/react/useDebugValue)
useDebugValue ist ein React-Hook, mit dem sich Zusatzinformationen in den React DevTools anzeigen lassen. Im Kern eine Art strukturierter Debug-Output, der besonders hilft, wenn dieselbe Komponente mehrfach im Tree auftaucht.
[] Debugging in React & DevTools (react.dev/learn/debugging-react)
Wir vergleichen klassisches Browser-Debugging mit React-Debugging und diskutieren, warum React eigene DevTools braucht: synthetische Events, virtueller DOM und eine parallele Realität zur Web-Plattform.
[] Web Components & Custom Elements (developer.mozilla.org/en-US/docs/Web/API/Web_c…)
Exkurs in die Welt der Web Components: Warum Debugging dort oft einfacher ist, weil es keine virtuelle Abstraktion gibt – und was passiert, wenn ein Custom Element nie registriert wird. Spoiler: Der Browser bleibt erstaunlich gelassen.
[] Kaputtes HTML & Browser-Parsing (html.spec.whatwg.org)
Wir diskutieren, warum Browser kaputtes HTML akzeptieren müssen, weshalb XHTML sich nie durchgesetzt hat und warum ein strikt validierender Browser automatisch ein schlechter Browser wäre.
[] React isValidElement() (react.dev/reference/react/isValidElement)
Ein eher unbekanntes React-API zur Laufzeitprüfung von React-Elementen. Wir schauen unter die Haube, stolpern über interne Marker wie $$typeof und landen bei Cross-Realm-Problemen.
[] TypeScript any vs. unknown (typescriptlang.org/docs/handbook/2/narrowing.h…)
Ein zentrales Thema der Folge: any als kompletter Opt-out aus dem Typsystem versus unknown als sichere Grenze. Wir erklären Typ-Hierarchien und warum unknown fast immer die bessere Wahl ist.
[] TypeScript: unknown als Sicherheitsgrenze (typescriptlang.org/docs/handbook/release-notes…)
Wir sprechen über reale Einsatzszenarien, etwa bei fetch(), und warum ein sauberer Typ-Reset oft sinnvoller ist als das blinde Akzeptieren von any.
[] TS-Reset & Fetch-Typen (github.com/total-typescript/ts-reset)
Ein Community-Projekt, das TypeScript-Defaults bewusst verschärft. Wir diskutieren Chancen, Risiken und warum solche Tools sowohl helfen als auch schaden können.
[] TypeScript Function Overloads (typescriptlang.org/docs/handbook/2/functions.h…)
Ein Pattern für robuste APIs: nach außen präzise Typen für gute Autocompletion, nach innen unknown für saubere Validierung. Besonders relevant für Library-Autor:innen.
[] TypeScript Decorators (typescriptlang.org/docs/handbook/decorators.html)
Wir sprechen über Legacy-Decorators, Standard-Decorators und warum "experimentalDecorators" oft mehr Probleme schafft als löst.
[] Symbol.hasInstance & instanceof (developer.mozilla.org/en-US/docs/Web/JavaScrip…)
Ein tiefer Abstecher in Runtime-Typprüfungen, mehrfach gebundelte Klassen und warum instanceof in größeren Codebases schnell trügerisch wird.
Diskutiert die Folge mit uns in unserem Community-Slack: draft.community
Transkriptvom Podcast bereitgestellt · Zeitmarken springen hin
Ich habe ja die heretische Position eingenommen, dass nicht zwingend jedes Webprojekt mit React gemacht sein muss. Kannst du mir dieses Wort kurz erklären? Die vom Glauben abgefallenen, die man irgendwie ans Kreuz oder ähnliche Dinger befestigen sollte. Die philosophische Frage dahinter ist, wer ist denn jetzt vom Glauben abgefallen?
Ich kann mich hier um die eigentlich wichtigen Dinge kümmern. Der Kiki seufzt schon die ganze Zeit. Ich glaube, ihm liegt echt was am Herzen gerade. Ich muss ja dazu sagen, dass ich eventuell in dieser Liste der Themen vorhin explizit das Thema Type Assertions aufgenommen habe. Ich finde schön, dass wir außerdem hingekommen sind.
Euro in den Hut werfen. Aus euren Beiträgen und den gelegentlichen Werbeblöcken bezahlen wir Domains, Server, diverse Software-Abos und natürlich das Honorar unserer Audio-Producerin. Danke euch allen für eure treue Unterstützung. Revision 694. Hallihallo Hallöle und herzlich willkommen zu Working Draft Revision 694.
Heute sind am Start der Stefan. Hallo Servus. Keine Sorge, wir haben auch einen Gast, nämlich den Kiki. Moin, Kiki. Moin. Und meine Wenigkeit, der Peter. Und weil wir einen Gast haben, wissen wir, es ist nicht das übliche, die gleichen zwei alten Männer drehen um immer das gleiche Thema, sondern drei alte Männer drehen um immer das gleiche Thema.
Keine Sorge, jetzt ist TypeScript Plus. Plus React, TypeScript und React. Minus mal Minus ergibt bekanntlich Plus. Und unter dieser Prämisse dachten wir, machen wir hier einfach mal so ein Mikro-Glücksrad. Es gibt ja leider keine React-Spezifikation und von TypeScript gibt es ja auch keine. Also habe ich buchstäblich die letzten 20 Minuten damit verbracht, Google zu fragen, gib mal Liste von React-Features, gib mal irgendwie so Liste von TypeScript-Features und habe die hier in so einen Google-Doc reingehauen.
Und wir losen jetzt einfach hier eine Zahl aus und schauen einfach mal, was wir da so als Stichwortgeber nehmen. Ich würde sagen, das machen wir. Stimmt's? So, wie kriege ich jetzt eine Zufallszahl hin? Ich schätze mal, ich frage einfach Google, oder? Number between. Du kannst einfach Chat-TVD fragen. Ich kriege das aber tatsächlich auch raus, ohne drei Seen auszutrinken. Pass auf, hold my beer.
Zahlen kann der ja nicht so gut. Wie viele Entry haben wir dann? 76. Pass auf, pass auf. Ich habe eingegeben, number between. Und dann sagt mir die KI-Übersicht, dieses brillante Tool. Eine Nummer zwischen 1 und 76 könnte theoretisch jede Zahl zwischen 2 und 75 sein. Das ist wahr. Das ist streng genommen nicht verkehrt.
Andererseits verstehe ich auch nicht, wie man die Frage, die ich jetzt hier in die Suchbox gestellt habe, so interpretieren kann, dass ich erklärt bekommen muss, was das Konzept von so einem Intervall ist. Ich weiß es nicht. Aber es gibt numberrandomgenerator.org. Nehmen wir doch den. Also während du das jetzt gemacht hast, habe ich im Terminal den Node-Reppel aufgerufen, habe mathrandom mal 76 plus 1 eingegeben und wir sind bei 16.
Okay, zufälligerweise sind wir jetzt bei 16. Wunderbar, das ist doch exakt das, was mein Zufallszahlen-Generator ausgespuckt hat. Also müssen wir jetzt über 16 reden. Ah, das ist super. Das ist ein React-Hook, von dem ich tatsächlich heute zum ersten Mal was erfahren habe. Ich mache das ja schon länger nicht mehr, außer wenn ich halt irgendwie exorbitant gut bezahlt werde.
UseDebugValue. Was ist denn das? Weiß das jemand? Ja. Ja, der ist schon bei mir vorbeigeflattert, aber ich habe ihn tatsächlich noch nie aktiv verwendet. Für mich war er zu spät da, glaube ich, wenn ich mich nicht vertue. Oder ich habe ihn damals sicher geguckt bekommen. Ich wollte den mal haben und bin dann irgendwann, wie viele Jahre später, darüber gestolpert.
Also Grundidee, wenn ich mich nicht vertue, ist, React hat ja diese wunderschönen DevTools. Komplett unterbewertetes Feature, sollten viel mehr Technologien mit sich bringen, damit man nicht immer nur die Chrome DevTools aufmacht und den großen AI-Button sieht. Und man kann damit in eigenen Komponenten oder nur eigenen Hooks, bin ich mir nicht sicher, Informationen in diesen Dev-Tools rendern.
Wenn ich mich nicht vertue, nur Strings, das finde ich wiederum so ein bisschen schade. Ich fände es total geil, wenn ich da ein kleines Panel reinrendern könnte und tolle Features machen. Also wenn ich da eine React-Komponente am besten übergeben könnte. Aber ich glaube, das ist so die Grundidee, oder?
Tatsächlich ist es genau das. Also du kriegst dann in den React-Dev-Tools, Also wenn du auf eine Komponente klickst, im Hooks-Pendel genau diese Information angezeigt. Und zwar der Name des Hooks, den du schreibst, mit der String-Information, die du angeben willst. Okay, das ist also ein fancy Konsole-Log-Statement. Ja, also wenn du direkt auf die Dev-Tools raus.
Entschuldigung, aber wenn ich Konsole-Log mache, dann gehe ich auch in die Dev-Tools. Ich gehe in ein anderes Panel, aber an sich ist es das doch, oder? Ja, natürlich, aber du hast halt, wenn du in dem Konsole-Log drinnen bist, hast du halt nicht die Zugehörigkeit zur Komponente. Da ist ja dann der Konsole-Log wieder ein bisschen umfangreicher.
Aber ja, also es ist Convenience-Function für die React-Dev-Tools. Ja, für die React DevTools. Ich meine halt nur, du hast durchaus den Kontext von der Komponente, wenn deine Komponente keine React-Komponente ist. Wenn das irgendwie ein Diff ist oder so, kannst du das Ding ja mit reinschreiben in einem Konsole-Log und dann kannst du ja aus der Konsole das Ding inspizieren.
Also, ganz so magisch ist es ja nicht. Also könnte man schon machen, aber ich finde halt schon so, diese Zuordnung im Komponentenbaum ist halt schon ein Benefit, also wenn du Komponente 30 Mal auf der Seite verwendet hast, dass du dann schnell rausfinden kannst, welche davon ist es. Und natürlich hast du recht, dass man da auch das DOM-Element irgendwie in der Konsole ausgeben müsste, könnte, Entschuldigung.
Dafür müsstest du aber gefühlt erstmal eine Rev verwenden, um dieses Element zu bekommen. Und eventuell ist die Komponente noch gar nicht gerendert und dann ist das Element noch nicht da und das geht überhaupt nicht und um den DevTools geht's. Jaja, du musst halt nur verstehen, ich habe ja die heretische Position eingenommen, dass nicht zwingend jedes Webprojekt mit React gemacht sein muss.
Kannst du mir dieses Wort kurz erklären? Heretiker? Ja. Die vom Glauben abgefallenen, die man irgendwie ans Kreuz oder ähnliche Dinger befestigen sollte. Die philosophische Frage dahinter ist, wer ist denn jetzt vom Glauben abgefallen? Ach, weißt du. Eine Browser-Extension zu bauen um irgendwie besseres Debugging zu machen, sobald du es gemacht hast und nicht gerade im Prozess des Browser-Extension-Bauens bist, ist halt schon cool.
Das kann schon wirklich sehr viel Wert erschaffen. Es ist halt nur ein absolut unerträglicher Prozess, das halt zu machen, also in der Umsetzung der Browser-Extension zu programmieren. Das ist eine Strafe. Aber wenn es fertig ist und funktioniert, ist cool. Das stimmt schon. Da stimme ich dir zu. Ich möchte aber jetzt auf die Revision zurückweisen, die wir zu dritt schon mal gemacht haben, die 689, wo wir ja auch darüber gesprochen haben, dass wir uns in React immer in einer Parallelwelt befinden.
Das heißt, wir haben ja sämtliche Dinge entweder nochmal oder anders oder parallel zu denen, die tatsächlich im Browser existieren. Es gibt ein synthetisches Event-System, es gibt einen virtuellen DOM. Und deswegen brauchst du wahrscheinlich auch ein anderes Console-Log, um die Information richtig anzuzeigen oder zugehörig anzuzeigen.
Also alle Dinge, die du sagst, Peter, die passen, wenn ich nicht in diese Parallelwelt eintauche. Aber jetzt, wo ich im Upside-Down bin, das kleine Popkultur-Referenz, wer es nicht mitgekriegt hat, vielleicht brauche ich dann genau das und darum finde ich es gut. Also genauso, wie der Kiker das gesagt hat, hey, cool, DevTools gibt es dafür, das passt. Und wenn ich dann als Entwickler oder Entwicklerin die Möglichkeit habe, dass ich oder eingreifen kann, finde ich es auch gut.
Ich würde jetzt noch eine Frage an der Stelle Richtung Peter mal werfen, weil ich bin ja nur in der richtigen Welt, also da, wo es React und dergleichen gibt und nicht so bei Web-Components und den ganzen Zukunftstechnologien. Schön. Wenn ich eine Web-Component entwickle und die 30 Mal auf meiner Seite einbinde und ich ein Console-Log einbaue, was ausgeführt wird, bevor die DOM-Elemente erzeugt werden, weil ich möchte, du kannst mir gleich sagen, das geht nicht, weil ich irgendwie möchte, rausfinden möchte, warum liegt das Ding mir um die Ohren, warum rendert es gar nicht, was auch immer.
Wie kann ich rausfinden, welche Verwendung auf der Seite das verursacht? Kann ich das herausfinden? Ich habe immer das DOM-Element, in dem ich die Web-Component einbinde. Pass auf, pass auf. Ich komme auf dein Angebot zurück, zu sagen, das geht nicht. Weil die Web-Component ist das DOM-Element. Es gibt halt keinen virtuellen Rapper um das Ding drumherum.
Es herrscht halt eine 1-zu-1-Identität zwischen deiner Web-Component und dem Ding, das du renderst. Das Ding, das du erinnerst, ist die Komponente. Es gibt halt nicht mehr dieses darüber geordnete Konstrukt der React-Komponente zum Beispiel. Ich könnte jetzt widersprechen und dann in die Detaildiskussion einsteigen, aber das hilft nicht. Insofern würde ich das weglassen.
Ich bin mir ziemlich sicher, dass du nicht widersprechen könntest. Also du kannst es versuchen, aber... Ich habe ja keine Ahnung davon. Ich glaube, es ist nicht hilfreich. Das Ding ist halt wie so ein Diff. Von dem Diff gibt es halt auch nur so der Diff an sich. Und da gibt es halt keinen Zinnober drumherum.
Und eine Web-Component ist nichts weiter als ein Fancy-Diff, das du dir selber zusammengestrickt hast. Und alles, was halt für ein Diff gilt, gilt halt genauso für den Fancy-Kiki-Renderer 2000. Wenn wir von Web-Component reden, reden wir eigentlich von, nicht eigentlich, sondern geht es immer um dieses Custom-Elements-Gedöns, was wir erzeugen. Richtig.
Das ist meines Erachtens der Sprachgebrauch. Die API kann eine andere sein, weil man kann da irgendwie Abstraktionen drumherum bauen, wenn man sehr gerne NPM bedient, aber man kann es auch nackt machen, wenn man auf Schmerzen steht. Man kann es so oder so machen. Wenn ich jetzt ein Custom Element aufrufe, was es nicht gibt, was passiert dann so?
Aufrufe verwende. Du postulierst einfach, es gäbe ein Kiki-Renderer 2000, ohne irgendwelchen Code dafür zu schreiben. Kannst du bitte aufhören, Begriffe zu verwenden, wo ich die ganze Zeit nachfragen musste? Ich postuliere. Du benutzt einfach einen HTML-Tag, den es nicht gibt. Ja, genau. Was passiert dann?
Browser sagt, habe ich noch nie gesehen. Ich mache dann HTML-Unknown-Element drauf. Graus, das hat ungefähr den Feature-Umfang von einem Span. Man kennt das ja vom Browser. Du gibst dem was, was er nicht kennt. Wenn das so in HTML drin ist, unbekanntes Attribut, unbekanntes Element, kennt man ja auch irgendwie von Tippfehlern her.
Ich habe mal irgendwie H7 geschrieben versehentlich oder sowas. Dann macht er halt eben einfach weiter und sagt so, ich tue mal so, als wäre es ein Span und habe das nicht gesehen. Und wenn ich der Fall fest überzeugt bin, ich habe jetzt gerade meine Web Component H7 geschrieben, aber irgendwie wird der Code nicht aufgerufen, wie debugge ich das?
Da kannst du ganz einfach nachgucken ob das Ding in der Custom Element Registry drin ist das ist einfach ein Objekt ist es ja offensichtlich nicht sonst würde es ja da eingebunden werden wie. Ich drifte in eine komplett andere Richtung ab, die Ursache dafür kann halt nur sein dass du das nicht in die Registry reinsteckst also guckst du halt eben wo werden Sachen in die Registry reingesteckt und warum passiert das mit meinem Kollegen halt nicht Wahrscheinlich, weil irgendwie ein Modul nicht geladen wurde, solcherlei Kisten.
Aber das ist alles super basic, ne? Das kann mir durchaus einfach passieren. Also gibt es keine Typsicherheit, keine startische Code-Analyse, die irgendwie sowas überprüft, dass ich da nur Web-Components aufrufe, für die ich auch ein Custom-Element registriert habe? Gibt es jetzt nicht. Ich wäre es relativ trivial zu machen, weil es gibt da eine CSS-Pseudo-Klasse.
Das ist ja keine startische Code-Analyse mehr. Das ist dann ja... Nee, nee, das halt nicht. Statische Grundanalyse geht ja eh nicht, weil die Idee ist ja, du operierst ja auf der nackten Ebene der Webplattform selber und da müsste man ja tatsächlich berücksichtigen, sämtliches JavaScript, sämtliches TypeScript, sämtliches HTML, und was du sonst noch so an lustigen Nebenwirkungen da drin hast, du könntest ja in deinem HTML ein Skript drin haben mit einem Eval-String, der ein Modul lädt, wo dann die Web-Component sich drin manifestiert und das ist halt eben nicht so generalisiert statisch lösbar.
Was ich halt machen würde, ist, es gibt die CSS-Pseudoklasse Defined. Die trifft halt zu auf Elemente, die definiert und bekannt sind. Und man kann sich ja ganz einfach mit Notch Defined irgendwas basteln, was Alarm schlägt, sobald irgendein Element darauf matcht. Ja, ich finde das schade. Habe ich nicht kommen sehen, aber wir sind ja gar nicht in der Web Components vs. React Folge.
Die gab es ja schon, oder? Ich weiß nicht, ob es die schon in der Form gab. Außerdem muss ich das ja nicht auslesen. Du kannst ein Web Component bauen und du kannst ja irgendwie mit Preact oder mit React zum Beispiel, wenn du zu viele Kilobytes zu verschleudern hast, kannst du ja das Innenleben mitgestalten. Ist ja kein Problem.
Ach, kurzer Einwurf. Wir sind immer in der Web Components vs. React Episode. Ach so, okay. Also wenn ich dabei bin, jedenfalls. Ja, okay. Also wenn du Components haben willst und du willst sowas mit Schattesanalyse haben, dann musst du halt eben einfach einen Überbau konstruieren, der React gleich halt eben sagt, ich bin halt nur durch zum Beispiel TypeScript steuerbar.
Und dann kannst du halt eben sagen, innerhalb dieses Realitätstunnels, den du da konstruiert hast, kann ich Schattesanalyse machen. Aber so in der Naturversion, wo halt irgendwie alles kann und nichts muss, da kannst du halt eben auch keine Schattesanalyse draufbauen, weil du halt eben nicht notwendigerweise statisch analysierbares Material hast.
Ja, danke. Wieder was über Web-Components gelernt. Ich habe jetzt Type-Safe-Web-Components in Google eingegeben und seitdem geht es mir deutlich schlechter. Deswegen würde ich einfach wieder zu Usd-Mark-Mail zurückkehren wollen. Das ist, als würdest du sagen, Type-Safe-HTML. Das funktioniert halt eben nicht. Das ist irgendwie... Aber also...
Ich dachte, wir sind aus dem Zeitalter raus, wo wir einmal... Wie hieß denn dieser Check? Der hieß nicht Self-HTML? Das war die Doku. Wie hieß dieser Validator, den wir alle immer benutzt haben? Der ganz normale HTML-Validator? Der hatte doch so einen Namen vor 15 Jahren, nicht? Der W3C-Validator. Ist ja wirklich einfach nur so. Das ist ja langweilig.
Aber ich meine, den gibt es auch noch, nicht nur vor 15 Jahren, den kannst du heutzutage immer noch haben und der kann dir immer noch sagen, dass dein HTML passt oder nicht passt. Aber die Frage ist ja, was bedeutet denn nicht passen? Also weil du kannst ja sagen, mein Programmcode ist falsch, aber das kann sich ja ausprägen auf viele verschiedene Weisen.
Das kann sein, dass das Ding abstürzt oder halt irgendwie was falsch darstellt, die Pixel sind verschoben oder alles halt eben zwischendrin. Und der Fehlermodus von HTML ist halt irgendwie tatsächlich zu sagen, okay, ich habe hier ein Passerror, nicht wie stürze ich ab, das wäre XHTML gewesen, sondern der ist, okay, welchen, Fehlerkorrekturmechanismus fahre ich jetzt an, damit ich weiter dieses Dokument verarbeiten kann.
Es gibt ja nicht wie in XML dieses Dokument ist nicht wohlgeformt, weil da irgendwie ein Quote fehlt, sondern da rollt einfach der HTML-Panzer immer weiter und lässt sich durch nichts aufhalten. Ich, Finden wir das gut? Mal ganz kurz. Sagen wir mal so, es hat halt historisch bedingt, glaube ich, mehr Sinn gemacht, als halt dieser ganze Webkram nicht nur die Domäne von irgendwelchen Turbonerds waren, die sich überhaupt solche Fragen stellen, wie wir jetzt gerade, sondern wo halt irgendwie auch der Hobby ist, der einfach irgendwie nur so Beef mit seinem Bürgermeister hatte, einfach mal eine Webseite irgendwie, wo haben wollte.
Da war das halt, glaube ich, schon noch viel notwendiger als jetzt. Also, glaube ich, egal. Ich meine, wer Wer das nicht haben will, der kann ja theoretisch immer noch mit XML zu Werke gehen. Das ist ja dann validierbar und legt sich sofort die Karten, sobald irgendwo mal was nicht passt. Das geht ja. Man kann ja heutzutage tatsächlich XHTML-Dokumente raushauen.
Das macht halt nur keiner. Und so denke ich halt eben auch, in der Theorie finden das, glaube ich, mehr Leute gut, als es in der Praxis passiert. Weil wenn das in der Praxis irgendwer gut fände, dann wäre nicht alles mit Doctype HTML versehen, sondern dann wären das alles XHTML-Dokumente. HTML5 ist ja die DOM-Struktur das ist ja was die Spezifikationen beschreiben und es gibt zwei Serialisierungen dieser DOM-Struktur das eine ist HTML, die andere ist XML aber die deserialisieren am Ende zum gleichen In-Memory-Baum-Modell, das heißt jeder von uns könnte sofort hingehen und könnte XHTML-Dokumente bauen dann wäre alles super strikt und statisch und hast du nicht gesehen, das macht halt keiner und das zeigt mir, dass das irgendwie glaube ich niemanden so wirklich kümmert.
So, und wenn du nach meiner Meinung fragst, wie finde ich das, würde ich sagen, das ist halt irgendwie so, als würdest du mich fragen, wie finde ich denn den aktuellen Wert der Gravitationskonstante, weißt du, das ist halt so und das kriegen wir auch nicht mehr geändert und muss man sich halt mit abfinden und die Rakete entsprechend dimensionieren.
Da bin ich ausgeschicken. Ich hätte zwei Dimensionen, über die ich mal sprechen wollte, würde mal gucken, ob das sinnvoll ist. Zwei Dimensionen kriege ich noch hin. Schieß los. Ich fange mal mit dem, glaube ich, einfacheren an. Das ist das erste Thema gewesen, nämlich dieses Type-Safe-HTML oder so. Und letztendlich auch dein CSS-Selektor. In meiner Welt ist es so, dass statische Code-Analyse sinnvoll ist, weil sie ermöglichen, schnell auf potenzielle Fehler hinzuweisen, dass sie potenziell Effizienz beim Entwickeln erhöhen, weil du eben nicht erst in den Browser gehen musst, sondern dass direkt in deiner IDE rot unterklingelt wird, wenn du es falsch schreibst. 100 Pro.
Und die CI-Pipeline nicht 48 Stunden läuft, sondern halt nur 48 Sekunden und so weiter. Und insofern muss ich sagen, finde ich es immer schön, je mehr ich statisch analysieren kann. Und ich erinnere mich damals zu AngularJS 1 Zeiten, dass mich das total frustriert hat, dass da eben alles so super dynamisch war, ähnlich wie du das jetzt gerade von Web Components schilderst, dass man eben nicht schon im Compile-Schritt oder was auch immer, den es wahrscheinlich in deiner Welt gar nicht gibt, schon im Compile-Schritt sicherstellen kann, dass das, was man aufruft, tatsächlich existiert.
Ja, also ich gehe 100% mit, dass in einer Welt, die so funktionieren würde, sich viele Fehler vermeiden ließen. Nur der Naturzustand des Webbrowsers ist halt nicht diese Welt und du musst sie halt eben mit Aufwand erzeugen und dann kommen wir wieder zu React, wo das ja tatsächlich so ist. Da wird alles durch ein JavaScript-Nabelöhr durchgedrückt und das hat halt so diverse Nachteile, aber das hat halt unter anderem den Vorteil, dass es halt eben tatsächlich ein Regelwerk gibt, sie alle zu knechten.
Du kannst halt irgendwie alles so weitgehend der Kontrolle von TypeScript unterwerfen und damit halt eben diverse Fehler einfangen und bezahlst halt eben damit, dass du halt nicht direkt mit der Plattform redest, sondern halt immer so Dinger brauchst, die halt eine Brücke herstellen zwischen dem, wie es wirklich ist und dem, wie du es gerne hättest.
Und das ist halt eben dann so der Trade-off. Wie geht man damit um mit diesem Delta? Entweder man macht so Embrace the Chaos. Das wäre jetzt so meins. Oder man sagt halt eben, hier muss man Ordnung einziehen. Und du schwingst den großen Besen und sagst, das geht jetzt alles hier durch dieses Nadelhör durch.
Das ist halt eben Abstraktion, die ermöglicht. Ist ja ganz normales Programmier-Dings. Das ist alles irgendwie chaotisch. Lass mal da was drumherum basteln, was das Ganze irgendwie ordnet. Ist ja sinnvoll, ist ja etabliert. Kannst du machen. Ich habe dich gerade gefragt, finden wir das gut. Die historische Herleitung, warum Browser jegliches HTML schlucken.
Und die Tatsache, dass man sich leichter bei den Bürgermeister beklagen kann, das ist also Demokratisierung des Webs quasi, spitze. Aber wenn du heute den Browser des Web 5.0 sind wir wahrscheinlich gerade entwickeln würdest, würde der immer noch kaputtes HTML schlucken oder nur XHTML? 100 pro würde der kaputtes HTML schlucken, besser als alle anderen.
Das ist halt so die Grundvoraussetzung. Das ist das Eintrittsgeld, das du bezahlen musst, um überhaupt teilzunehmen. Das Ding ist halt, wenn du einen Browser hast, der kein kaputtes HTML schluckt, ist der instantan ein schlechterer Browser als alle anderen, weil der halt in der Lage ist, weniger Webseiten darzustellen als die Konkurrenz.
Ja, aber du bist ja jetzt im Web 5.0. Da gibt es ja das alte Web. Das alte Web ist ja langweilig. Das interessiert dich ja gar nicht. Du erfindest ja gerade alles neu. Okay. Wenn ich es neu erfinden würde, würde ich mir wahrscheinlich was Neues ausdenken. Aber was Neues zu erfinden, scheint mir halt mehr oder minder ausgeschlossen.
Also das halte ich für eine derart hypothetische Kiste. Das würde ich so ins Bücherregal in das gleiche Fach so mit der sowjetischen Fantastik reden, wo halt so die Gen-Engineers irgendwelche Drachen wiederbeleben, mit denen man dann durchs Universum fliegt. Okay, okay, okay. Ich habe es heute mit Vergleichen, die nicht funktionieren. Das habe ich im Termin vorher schon erfahren.
Ich hätte vielleicht einen besseren Vorschlag. Okay. Wir führen einen neuen Header ein, so wie Strict Transport Security, der sagt, wenn unter dieser Domain falsches HTML kommt, wirft das bitte weg. Den Heller brauchst du nicht. Du brauchst nur den Content-Type umzuschalten auf Application XML. Da hast du das bei dir. Es sei denn, meine Anwendung läuft amok.
Also mir geht's Was bedeutet amoklaufen? Der Tomcat, falls man es heute noch benutzt, ist abgeschmiert und irgendwas anderes antwortet komisch. Irgendein Anleitver hat sich dazwischen geklemmt in die Kommunikation. Ich habe keine Ahnung. Du willst also sagen, wenn in einer Applikation kein gültiges Zeug ausspuckt, ist kaputt. Und ich möchte gerne, dass der Browser sich dessen bewusst ist.
Also, dass der Der Browser weiß, diese Website hier spricht XHTML und wenn sie das nicht tut, dann ist was schiefgelaufen, dann wirft das bitte weg. Mach deinen Content-Type. Wenn du den Content-Type-Hater so setzt, dann nimmt der Browser zum Parsen deines Dokuments den XML-Parse und wenn daran was nicht passt, dann ist es. Vielleicht sollte ich erklären, warum ich da so drauf, warum ich von dieser Seite rankomme.
Also mein Gedanke ist, dieses Browser-Schlucken jeder Art von kaputtem HTML ist ja durchaus Wegbereiter für die ein oder andere Sicherheitslücke. Im Web gewesen. Und willst du da schon einsteigen? Ich weiß nicht, ob das bei HTML der Fall ist. Ich kann es nicht ausschließen. Ich glaube, es ist mehr so, dass, sagen wir mal, Design-Schwächen, wie irgendwie, dass du in einen On-Click-Händler beliebiges JavaScript reinschreiben kannst, wo das dann irgendwelchen Blödsinn-E-Welt, aber das ist ja kein ungültiges HTML.
Ungültiges HTML ist in meinem Kopf mehr sowas wie, du machst eine Table auf, aber ein Diff zu und der Browser stürzt daran nicht ab, sondern sagt halt eben, ah, das kenne ich schon, das mache ich weiter. Oder dein Body Tag fehlt oder irgendwie im Header ist ein P oder sowas. Das ist ja ungültiges HTML.
Viele der Angriffe, auch die mit dem erwähnten On-Click gerade, funktionieren halt aber nur, weil Browser am Ende das daraus resultierende kaputte HTML akzeptieren. Ja gut, das kann natürlich sein. Wenn du sozusagen an einer Stelle was kaputt machst, damit das mit evaluiert wird, was du an anderer Stelle auch noch reinjuckst, das kann ich mir vorstellen.
Du hast natürlich recht, dass saubere Trennung von Code und Daten irgendwie auch ein schöner Anfang gewesen wäre. Aber trotzdem dieses, wir probieren mal einfach rum. Ich muss gestehen, dass es bei mir gerade auch mehr ein Bauchgefühl ist. Also dieses Beispiel mit, man bricht damit aus dem HTML raus und dann bleibt da halt ein kaputtes HTML stehen und Browser schlucken, dass das existiert ja durchaus in der Realität.
Aber ich habe so ein allgemeines Bauchgefühl, dass dieses, wir probieren mal wild rum, wenn etwas nicht genau den Anforderungen entspricht, ob wir das nicht irgendwie doch noch auswerten können, dass das immer mal wieder viel bereiter für Sicherheitslücken war. Und deswegen habe ich da so ein, das wäre irgendwie cool, wenn wir es nicht mehr hätten und einen Header, den wir setzen, der eben dafür sorgt, dass bei weiteren Besuchen das immer noch abgelehnt wird, würde das Problem deutlich mehr mitigieren als so der Content-Type-Header, der halt nur für diese eine Response gilt.
Verstehe ich jetzt den Unterschied zwischen diesen beiden Header nicht? Weil in dem Moment, wo ein Angreifer da ist, sage ich jetzt mal, will ich mich darauf verlassen können, dass der Browser weiß, dass er das bei uns so interpretieren soll und nicht darauf spekulieren, dass in dieser Response auch noch der richtige Header mitgeschickt wird.
Ich kann mir gerade das Szenario nicht zusammenreimen. Also mit dem richtigen Header halt. Weil ich meine, Stand jetzt schaffen es ja alle Web-Server auf diesem Planeten völlig problemlos zu sagen, hier Content-Type-Text HTML. Und ich glaube, durch relativ einfache String-Substitutionen könnte man sie dazu bringen, dass sie dann sagen, Content-Type-Application-XML.
Und dann wären wir in der Welt, wo halt ungültiger Code nicht mehr akzeptiert wird. Das müsste halt nur jemand machen, der darauf Wert legt. Wie verhalten ein Browser sich, wenn ich keinen Content-Type-Header mit liefere? Das weiß ich nicht. Hätte ich auch gesagt. Und insofern würde ich behaupten, dass nicht jeder Web-Server diesen Content-Type setzt.
Na gut, aber ich meine, wir gehen ja von der Prämisse aus, dass wir jetzt operieren unter der Älgide vom strikten Kiki, wo ja ordentliche Entwicklung, mechanische Analyse schon mal Ausgangsposition ist. Und dann würde ich ja auch mal unterstellen, dass dir kein Server ins Haus kommt, den halt ich irgendwie mit 16 Jahren zusammengeschustert habe und der tatsächlich keinen Content-Type hat.
Ich bin ja aber gerade in der Situation, etwas ist mit dem System nicht in Ordnung, weil es jemand angegriffen hat, weil Tomcat zu viel RAM braucht, weil weiß ich nicht was. Und in der Situation kann ich mich auf diese Annahmen oder will ich mich auf so wenige dieser Annahmen verlassen müssen, wie möglich.
Okay, was du also gerne hättest, wäre ein Browser, der tatsächlich kaputtes HTML nicht akzeptiert. Du willst nicht für dein Projekt ein Opt-out machen und sagen, so hier, alles, was meine Agentur liefert, ist jetzt irgendwie Application XML, sondern du willst, dass die Clients tatsächlich nicht in der Lage sind, kaputtes HTML so zu verarbeiten, wie sie es im Moment tun.
Ich bin fein damit, wenn ich ausopten muss, aber das soll dann bitte für meine Domain persistierbar sein, ähnlich wie bei diesem Ding mit meiner Domain bitte nur noch bei TRS 1.2 aufrufen. Eigentlich war ich bei der Frage, ob du das für eine gute Idee hältst oder nicht. Ich glaube die Ziele von Qualität und Stabilität lassen sich auf anderem Wege einfacher erreichen und deshalb würde ich vorschlagen die Ressourcen anderswohin zu konzentrieren, ergo keine so besonders brillante.
Dann bleiben wir einfach dabei, dass wir UseDebugValue verwenden und dann lass das Problem auch weg. Ja genau, ne ConsoleLog oder hier DebuggerStatements in den Code reinbauen, dass du so, dass du alles neu kompilieren musst und fancy DevTools benutzen kannst. Ja okay. Okay, wollen wir ein neues Thema uns picken? Ja, Nummer zwei, yay.
Moment, mache ich wieder den Zufallsgenerator. Ich habe meine Konsole immer noch offen und ich drücke einfach die gleiche Zeile nochmal rein. Und wir sind bei 42. Klar, sicher sind wir bei 42. Natürlich, ich glaube, das sind nicht die einzigen Zeilen, die ich ausspucken kann. Is valid element? Ist das eine Überleitung, oder? Wir haben die ganze Zeit über HTML-Validität gesprochen. Wir haben jetzt tatsächlich die Funktion Is valid element?
Nein, nein, nein. Das guckt, ob der Value, den du da reinsteckst, ein gültiges React-Element ist. Also ich muss jetzt erstmal unterbrechen. Als ich hier gerade geguckt habe, was die Nummer 42 war, stand da was komplett anderes und die 44 war leer. Und jetzt ist das von der 42 in die 44 gerutscht und da ist was Neues.
Ich glaube, Peter hat sehr bewusst. Also ich kann tatsächlich sagen, das Dokument hat sich in der letzten Zeit nicht geändert. Ich glaube, das dürfte bei dir noch ein Update-Problem gewesen sein. Aber das hat bei mir jetzt schon immer so ausgeschaut. Ich hasse das Internet. Aber die wichtigere Frage ist, Hast du auch Hass auf isValidElement?
Nee, ich glaube, dass ich das um ehrlich zu sein habe, auch super selten. Ich glaube, dass im Kontext von React Children Map habe ich das mal benutzt und dann halt es auf und irgendwie. Also, wenn du Children angibst, willst du natürlich auch überprüfen, ob das Elemente sind, damit du die renderst? Eventuell, aber ich bin mir nicht sicher. Also, wenn du euch diese Funktion auch noch nie verwendet.
Also, ich bin beeindruckt, dass es die Funktion gibt. Ich habe die nun nie verwendet. Ich finde das total cool und ich habe gerade gesehen, dass Legacy ist. Das heißt, wahrscheinlich sollte man es dann eh nicht mehr verwenden. Peter, kennst du das? Nö, tatsächlich habe ich das auch beim Zusammenstellen der Liste hier zum ersten Mal gesehen.
Aber natürlich wandert mein seltsames Gehirn jetzt direkt schon mal los. Und er fühlt sich erinnert an Array is Array. Das gibt es ja auch. Und das hat ja diese wunderbare magische Eigenschaft, dass es dir ja sagen kann, in Browsing-Context 2 angewendet auf ein Array aus Browsing-Context 1, jupp, das ist 1.
Das braucht nicht wie Instance-Off den Constructor und das Objekt aus dem gleichen Browsing-Context zu haben. Das kann über Frame-Grenzen hinweg und Ähnliches, dir das ja sagen. Musste ich letztens tatsächlich mal basteln, also sowas extrem Ähnliches aus ganz anderen Gründen, aber letztlich so die gleiche Problematik.
Musste das also zu Fuß mal implementieren, sowas in der Richtung. Und jetzt frage ich mich natürlich, ob dieser Kollege auch Cross-Browsing-Kontext funktioniert. Wahrscheinlich nicht, weil er braucht ja keiner. Aber es wäre natürlich ein Flex, wenn es das könnte. Das Ding geht ja wirklich nur wieder auf die Parallelwelt. React los, ist valid element.
Ja gut, aber die Parallelwelt kannst du ja implementieren, wie du willst. Und du kannst sie ja auch so implementieren, dass sie Cross-Browsing-Kontext-Vergleiche richtig macht. Also was ich jetzt nicht kaum sehen habe, ist, dass ich jetzt den Quellcode von React gucke, während dieser Post-Cast-Folge. Ich bin auch gerade dabei.
Da ist es. Type of Object, das darf nicht in der Nähe sein. React Element Type, das klingt was zu alles, dollar dollar, type of. Das ist die Parallelwelt-Type-Off von React. Ja, das ist super. Einfach irgendwie ein F-Fix davor packen und dann passt das schon. Das hätte von mir sein können. Ja, ich finde es sehr schön. Also die Dokumentation sagt ja auch, dass es wirklich Elemente überprüft und nicht Nodes.
Also du kannst ja einen Text-Node zum Beispiel haben und solche Sachen. Auch in React? Auch in React. Also es gibt React-Nodes und React-Elements. Das weiß ja jeder, der übrigens die React-JSX-Typen auf... die es noch mal gesehen hat. Und was ja wieder diesen Parallelweltgedanken unterstützt, ich glaube das einzige Thema ist, über das ich in der heutigen Episode reden werde.
Aber es ist herrlich, oder? Also es ist ja wirklich eine genaue Spiegelung von dem, was wir nachher tatsächlich in den Browser haben wollen. Und sie referenziert hat auch die Nummer 42, was natürlich schön ist, weil es bei uns auch die Nummer 42 war. Frage an der Stelle, Symbol4 liefert in zwei verschiedenen Browser-Kontexten ein anderes Ergebnis, oder?
Das gleiche. Das gleiche. Dann halte ich es für möglich, dass es funktioniert, weil sie nutzen Symbol4. Bin mir noch nicht ganz sicher, was dieses $-Type-of ist, ob das tatsächlich irgendwie bei irgendeiner Form von Serialisierung verloren geht, aber auf den ersten Blick glaube ich, das ist einfach eine reguläre Property und klappt.
Ja, sehe ich genauso. Also dieses Symbol4 ist halt so das einzige Ding, womit man tatsächlich nicht Objekte, aber Symbols halt draufbeschwören kann, die dann in unterschiedlichen Frames das gleiche referenzieren. Das heißt, das Ding wäre tatsächlich Cross-Browsing-Kontext-Vergleichs-safe. Ich frage mich halt, ob das jemals irgendwer benutzt hat.
Ich war ja letztens in so einem Workshop von dir, in dem es auch um Symbols und Cross-Browser-Kontext ging. Also wahrscheinlich hast du das da auch erwähnt. Ja. So ein Bissl macht es aber auch das Konzept von Symbols kaputt, oder? Nö. Wo ist der Benefit von Symbol 4 gegenüber dem String, den ich dem Symbol 4 übergebe?
Kack jetzt, in einem öffentlich aufgezeichneten Podcast oute ich mich als dumm. Das ist wirklich ungeschickt von mir. Nein, nicht als dumm. Du hast recht, auf eine gewisse Weise. Du outest dich nur, dass du die nötige Referenz nicht griffbereit hast, weil die nächsten Developers wissen ja nicht alles, sondern die wissen, wo sie es holen müssen.
Ja, ich weiß, dass Peter fragen muss. Zum Beispiel das und zum anderen ist es ja auch schon mal ein Zeichen von einer gewissen Brillanz überhaupt zu erkennen, dass es da eine semantische Überschneidung gibt und dass es sich vielleicht lohnt herauszuarbeiten. Gibt es da einen Benefit? Wo sind die Gemeinsamkeiten? Wo sind die Unterschiede?
Das musst du ja auch erstmal erkennen. Also erstmal, grundsätzlich ist so, ja, du kannst mit dem String, wenn du den String hast und du im JavaScript drin bist, kannst du das gleiche Symbol heraufbeschwören. Du hast halt nicht mehr dieses Privacy-Feature, wenn die Variable irgendwie in der Closure steckt, kommst du nicht mehr ran.
Und insofern ist es tatsächlich so, dass so ein registriertes Symbol ein etwas seltsamer String ist. Was sind die Benefits? Benefit Nummer eins, definitionsgemäß non-enumerable. Das Ding wird dir also nicht in einer For-In-Schleife oder Object-Keys oder sowas entgegenfallen. Und zum anderen ist es so, es kann halt nicht versehentlich heraufbeschworen werden, indem ich diesen String in ein Formularfeld eintippe.
Wenn du sagst, hallo hier Peter, ich habe eine neue Web-App gevibecodet, probier mal aus, dann kannst du dir sicher sein, dass mein Vorname unterstrich unterstrich proto unterstrich unterstrich lautet. Einfach nur um rauszufinden, ob da denn alles irgendwie ordentlich funktioniert oder ob man da irgendwie durch komische Eingaben was kaputt machen kann und das kann ich halt mit Symbols nicht mehr machen.
Ich finde es ja sehr spannend, dass Sie zwar auf der, also bei diesem Dollar-Dollar-Type-off-Property zwar auf der Assignment-Seite mit Symbols arbeiten, aber nicht Dollar-Dollar-Type-off auch als Symbol abbilden. Das würde sich echt anbieten, weil dann hast du nämlich genau den ganzen Enumerationsblödsinn nicht mehr.
Bei Dollar-Dollar-Type-Off kannst du enumerieren. Ja, die Frage ist halt, also weil solche APIs sind ja quasi, also es ist ja nicht so, dass privat und nicht privat so ein Binary ist, weil du hast ja so Dinge wie Debugbarkeit. Also du schreibst irgendwie so ein React-Node irgendwie in die Konsole und dann willst du ja irgendwie, also dann ist es ja schon ersichtlicher, wenn du im Debug-Modus bist und wo dann die Variablen-Namen nicht minifiziert sind, dass du da erkennen kannst, okay, Dollar, Dollar, das ist irgendein internes Ding. Das habe ich nicht versehentlich da reingeschrieben.
Das heißt überall immer das Gleiche. Ich habe da so eine grobe Idee von. Das ist halt viel sprechender, als wenn du da diesen komischen Zahlen, nee, diesen Symbol Klumpatsch da hast, der halt mit einem Symbol-Key da einhergeht. Ja, da kann dann auch eine Description drinstehen. Aber die ist dann halt zum Beispiel auch immer da und wird halt eben nicht dann wegminifiziert, wenn du das kompilierst und so.
Also ich glaube, da gibt es halt schon so Überlegungen, wenn du an so einem großen Rad drehst wie React, wo du dann wirklich überlegst, okay, es gibt Gestaltungsüberlegungen für die APIs, die normale Menschen nicht benutzen sollen, aber diese Überlegungen betreffen halt die normalen Menschen. So wie du halt irgendwie auch überlegst, was ist irgendwie das beste Warnschild, das ich da aufklebe, auf irgendwie, was gefährlich ist. Okay, das verstehe ich.
Ich hätte auch noch die These, dass im Zweifelsfall dieses Dollar oder Type of Älter ist als Symbols. Bestimmt. Aber ist auch noch eine These also ich muss gestehen diese Datei React.js, Element.js könnte ich jetzt auch noch länger lesen das ist schon extrem unangenehm, was hier passiert ist wieso unangenehm?
Ich weiß nicht, wo ich anfangen soll nimm irgendwas? Da wird halt an ein paar Stellen den String zurückgegeben dieser String ist, Spitze Klammer auf, Pünktchen, Pünktchen, Pünktchen Spitze Klammer zu. Ich habe Fragen, wann dieser String jemals eine sinnvolle Rückgabe ist. Das scheint nur Dev-Mode eventuell. Nee. Nehme ich zurück.
Ich verstehe also, ich fühle mich beeindruckt, wie ich überhaupt kein Wort von diesem Code verstehe. Wie hier Sachen passieren, die ich noch nie gemacht habe, dass hier eine Auflistung von JavaScript-Engines an Variablen dran steht. Dann bin ich hier über so ein No-Inline-Annotation gestolpert. Wo ich Vermutungen habe, was sie tun könnte, aber zuletzt habe ich davon gehört, als ich mich mit GCC befasst habe und das habe ich jetzt nicht in JavaScript-Code kommen sehen.
Und weißt du, was du denn als nächstes machen solltest? Dann machst du mal React zu, nimmst dir Preact und liest mal den Code. Der ist schöner, oder? Nein, aber Größenordnungen weniger. Größenordnungen weniger schön oder weniger schlimm? Ich würde ihn nicht notwendigerweise als weniger schlimm, wenn man jetzt so irgendwie die Ästhetik-Überlegungen von irgendwelchen Normies da anlegt, würde ich jetzt so nicht sagen.
Das ist jetzt nicht irgendwie, also weil die halt eben schon echt ziemlich brutal darauf hin optimieren. Wir hatten ja auch, glaube ich, mal jemanden aus dem Pre-Act-Team, der darüber erzählt hat, wie sie halt eben das so hinkriegen. Also wie sie den Code schon so schreiben, dass sie dem Minifier zuarbeiten, damit er auch immer schön nur so und so viele Variablen macht.
Ich meine, der älteste Trick ist natürlich irgendwie zu sagen, Wenn ich ein leeres Array haben will, mache ich nicht Eck hier, Klammer auf, Eck hier, Klammer zu, weil es sind ja zwei Zeichen, sondern ich mache einen Variablen-Namen namens empty Array, weil empty Array kann runtergekürzt werden zu einem Zeichen von dem Minifier.
Solche Überlegungen sind da halt eben im Code drin und ich weiß nicht, Gigi, ob das jetzt wirklich dann deinen ästhetischen Überlegungen zuträglich ist, wenn man sowas macht. Aber es ist halt unglaublich wenig. Code? Oder schlimm? Code. Und nicht irgendwie jetzt obfuskiert oder irgendwie midifiziert mit Trollung, sondern tatsächlich halt eben mit Überlegung und Bedacht.
Das ist jetzt wirklich so rein auf der ästhetischen Ebene. Das sieht halt genauso wie Line Noise aus wie irgendwie Rust Code. Kann man jetzt dann finden, wie man möchte. Aber es ist halt auf jeden Fall einfach schon sehr viel krass, was halt eben alles in React drin ist und was in Preact nicht drin ist.
Und dann ist es halt trotzdem so in erster Nährung 99 Prozent gegeneinander austauschbar. Da fängt man dann an drüber nachzudenken, was macht man hier eigentlich? Ich bin immer noch auf der RealCodebase hängen geblieben. Ich habe jetzt auch reingeschaut und die, glaube ich, schaltest du wieder weg. Genau. Hey, wollen wir nicht vielleicht lieber auf eine zufällige Zahl umschalten? Ja, natürlich.
Sehr gerne. Also ich werfe diesen Zufallsgenerator wieder an und die sind bei 69. 69. Nice. Und damit entern wir Typescript-Land. wenn ich mich nicht ganz täusche ah ist das schön, Go off, King. Nein, was will ich dazu sagen? Was ausgewählt wurde, ist unknown. Und unknown ist das etwas striktere any.
Also man muss sich das TypeScript-Typ-System so vorstellen, dass du versuchst, in jedem Wert, der existiert, in einer Wertemenge zu klassifizieren. Also du kannst sagen, dieser eine Wert ist zum Beispiel ein String, dieser andere Wert ist eine Number. Dann gibt es verschiedene Objektwerte, die man mit entsprechenden Objekttypen klassifizieren kann.
Und die bewegen sich alle in einer ganzheitlichen Menge. Und die Aufgabe vom Typsystem in TypeScript ist, dass du in dieser Menge richtig navigierst, um richtig zu validieren, ob dieser Wert auch dieser einen Teilmenge davon entspricht. Und da gibt es jetzt zwei Typen, die die gesamte Menge darstellen.
Jeder Wert ist kompatibel zu diesem Typ. Das eine ist Any und das andere ist Unknown. Und dann ist ein bisschen so ein Ausbruch gewesen aus TypeScript, um mit dem, was in JavaScript tatsächlich passiert, auch umgehen zu können, weil in JavaScript passiert halt einmal sehr viel, das am Typsystem aktiv entgegenwirrt, sagen wir mal so, und heißt das, dass jeder Typ zu Any-Kompatibel oder jeder Wert ist zu Any-Kompatibel und du kannst auch, so wie dieser Wert mit Any-Kompatibel ist, auch alles damit machen.
Du kannst dir das Property aufrufen, du kannst ihn in jede Funktion reinstecken, du kannst einfach alles damit tun. Und weil das nicht besonders sicher ist, gibt es den Alternativtyp unknown. Unknown lässt dich gar nichts machen. Es ist zwar auch jeder Typ und jeder Wert mit unknown kompatibel, das heißt, jeder Typ ist eine Teilmenge von unknown, aber du darfst nicht, also eigentlich gar nichts damit machen, bevor du nicht konkreter angibst, welcher Subtyp das ist, indem du entsprechende Typeguards ausführst, wie, keine Ahnung, Type of String oder Property in irgendwas, also die ganzen Dinge, die man halt macht, um.
Sich bewusster zu sein, welcher Typ dann tatsächlich dahinter steht. Und ich habe das sehr cool gefunden, also ich habe das jetzt schon einige paar Mal präsentiert, wie jetzt der Unterschied zwischen Annie und Unknown ist und wie sich das im Typsystem verhält. Und einer hat es ganz gut auf den Punkt gebracht, wie er gesagt hat.
Tatsächlich widerspricht Annie somit dem Liskowschen Substitutionsprinzip, wo du eben sagen kannst, du kannst Dinge von einem, ich kann es nicht rezitieren in diesem Fall, Aber es geht darum, alles, was beim Übertyp möglich ist, soll auch beim Subtyp möglich sein. Ich glaube, das ist die Kernaussage davon.
Mit Any stimmt das nicht, weil du kannst Dinge auf Any ausführen, die nicht auf den Subtypen ausführbar sind. Mit Anon bist du auch wieder in diesem Substitutionsprinzip drin. Das heißt, das entspricht wieder dem Substitutionsprinzip. Ich fand das extrem aufregend, auf welchem Niveau du gerade Anon erklärt hast.
Und neigte schon zu dem Begriff akademisch und war jetzt drauf und dran, in diese Lisskopf-Diskussion einzusteigen. Das wäre dann noch akademischer und ich will deswegen nur in einem Satz dazu sagen. Ich glaube, ich würde nicht die Annahme treffen, dass alles andere ein Subtyp von Annie ist. Und in dem Moment, wo man diese Annahme nicht trifft, ist es auch wieder kein Widerspruch zu Gliscope.
Also technisch schon in der Anwendung würde ich es auch nicht machen. Ich würde es andersrum sagen. Ich würde sagen, dass Annie ein Subtyp von allem anderen ist und nicht alles andere ein Subtyp von Annie. Naja, aber das stimmt ja nicht. Weil jeder beliebige Wert, den du nimmst, ist kompatibel zu Annie. Warte.
Und das bedeutet nicht, meiner Meinung nach bedeutet das nicht, dass jeder beliebige Typ ein Kind von Annie sein muss, sondern das wäre auch andersrum der Fall, oder? Ja, das ist aber jetzt glaube ich ein assoziativer Typ, das heißt, du kannst halt quasi die... Nein, ist schwierig. Ja, ich glaube, das war der Partner. Ich glaube, es ist schwierig, weil tatsächlich... Also in meiner Blitzbirne ist Annie halt einfach ein Opt-out aus, was immer TypeScript da macht.
Du hast zu versichten, du hast zum einen das Typsystem und wie die Typen angeordnet sind und du hast halt ganz klar der Obertyp über allem. Die Frage ist aber das, wie verhält es sich bei den Typchecks? nachher nicht. Und da ist tatsächlich dieser Cop-out. Da ist dieses, okay, was immer passiert, vertrau mir, ich mache das Richtige oder auch nicht, was auch immer.
Und du deaktivierst sämtliche Checks, die der TypeScript gibt. Also das ist der tatsächliche Effekt davon. Genau. Von einem Ende. Das du eben bei anderen nicht hast. Aber in der Typ-Hierarchie ist trotzdem Ende noch über allen anderen Typen. Du hast ja auch unten Subtypen, die Subtypen von allen anderen Typen sind. Wie zum Beispiel Never.
Also Never ist die leere Menge, da hast du keinen Wert drinnen und das ist tatsächlich eine Teilmenge von jeder anderen Menge und hat halt andere Regeln. Also da kannst du halt davon ausgehen, dass du, wenn du never hast, was ja per Definition keinen Wert hat, dann kannst du diese auch, wie ich rede es jetzt.
Ich erkläre es gar nicht. Naja, ich kann... Warum ist es einfach so nicht? Ich kann gleich mal erklären, warum es dir so schwer fällt, das zu erklären. Ja, weil ich mein Chart nicht dabei habe. Das ist ein sehr visuelles Thema. Meine Analogie ist, ist immer das, never ist ja quasi die Null. Im Sinne von, das ist leer, da ist nichts.
Und die Null ist ja tatsächlich... Die Leermenge, das ist wichtiger als wie Null, weil tatsächlich hast du ja null als Wert in gewissen Typen auch. Ja, ja, aber Indem ich Null als Wert habe, ist es ja ein Wert, ergo ist Null, nicht Null. Das Einzige, was wirklich nichts ist, ist ja never. Und ich finde halt eben sehr erhellend, wenn man sich halt irgendwie mal vor Augen führt, dass die Null ja tatsächlich etwas ist, was ja erstmal irgendwer erfinden musste. und dass halt irgendwie Weltreiche, wie irgendwie so die alten Römer und Konsorten, wunderbar klargekommen sind, ohne eine Null zu haben.
Die haben halt keine, sagen wir mal, Operationen durchgeführt, die haben keine Mathematik und ähnliches betrieben, wo sie die Null für brauchten. Das haben halt die Araber gebraucht, die halt fancy Geometrie betrieben haben und von denen haben wir uns das halt hinterher geklaut, aber du kannst wunderbar den ganzen Tag klarkommen, ohne Null zu haben.
Du musst nicht irgendwo aufschreiben, ich hab null Kühe, weil du hast halt keine Kühe, da ist halt nichts, da musst du nicht irgendwie ein Symbol für haben. Das brauchst du halt eben dann, wenn du halt irgendwie anfängst, okay, bescheuerte Edge-Cases zu machen, die eine Funktion, die immer eine Exception schmeißt, warum würde man das haben wollen?
Oder halt eben, wenn du so Typ-Level-Programmierung machen willst und du willst irgendwie Dinge filtern, indem du sie auf Never-Maps. Aber das ist ja tatsächlich schon eine Meta-Ebene entfernt von dem, was man als normaler Mensch macht, wo man nämlich sagt, das ist ein Array aus Zahlen oder ein Array aus Fuß oder was auch immer.
Und deswegen ist das halt immer so ein Kampf, das irgendwie einzuordnen in die Welt der real existierenden Dinge. Ich möchte aber noch kurz was dazu sagen, was der Hanses gesagt hat. Und zwar, ich verstehe, warum du das denkst, weil du kannst jetzt jeden Wert, der Any ist, zu jedem anderen Typ zuordnen.
Und du kannst jeden anderen Typ zu einem Typ vom Typ Any zuordnen. Also das geht auch. Von dem her kannst du Any da beliebig einsetzen. Und du hast da die Idee, wo ist es in der Hierarchie, es kann überall sein. Aber tatsächlich ist es nur ein Seiteneffekt davon, dass keine Checks gemacht werden mit denen.
Also das ist quasi dieses Copout-Feature. Das ist auch das, was mir als die Definition ganz schön gefällt. In dem Moment schaltest du TypeScript aus, da gibt es kein TypeScript. Alles, was diese Variable betrifft, ist TypeScript. Ganz vergessen. Ja, voll gut. Ich erinnere mich, dass ich schon mal bei euch zu Gast war und dass da ich dieses Projekt TS Reset irgendwie mal fallen gelassen habe, weil die so eine schöne Website haben.
Und das ist für mich auch so im Kontext Unknown, lasse ich das gerne fallen. Irgendjemand hat die Entscheidung getroffen, dass in TypeScript die Funktion Fetch ein Promise zurückgibt, was mit Any Resolved. Und das bedeutet, dass in dem Moment, wo wir einen HTTP-Request mit nativen Wortmitteln machen, TypeScript uns quasi abgeschaltet ist für die Rückgabe davon.
Und was TS-Reset unter anderem macht, ist eben das auf ein Unknown umzustellen, was letztendlich heißt, du musst erstmal prüfen, ob da wirklich das drin ist, was du erwartest, bevor du damit arbeiten kannst, was ich einen total guten Default finde an der Stelle gegenüber dem Any. Also es ist ganz eindeutig, warum.
Das nicht in Typescript selbst sein kann, weil Typescript ja versucht, jeden JavaScript-Code, der funktioniert, auch weiterhin als funktionierend darzustellen und nur offensichtliche Fehler darstellen will. Und da hast du an dieser Grenze, wo du I.O. Hast, also wo der Punkt ist, wo du dich auf die Eingaben von Pritz-System verlässt oder auf eine Benutzereingabe oder was auch immer, also nicht Teil dieses Systems, das du dir aufgebaut hast, immer einen Bruch.
Und mit diesen Brüchen geht TypeScript sehr, sehr lax um, bewusst, weil es ihm sagt, okay, in den meisten Fällen sorgt es für mehr Probleme, als wie sie tatsächlich lösen. Weil sie halt auch nicht davon ausgehen können, dass jeder halt irgendwie ausdefinierte Schemata für seine Endpoints hat. Ja, ganz genau. Oder du weißt ja gar nicht, ob du überhaupt irgendeinen Typen erwartest, wenn du einen Fetch Call machst.
Vielleicht willst du ja einfach nur, keine Ahnung, sofort damit herumwerken und was tun. Von dem her verstehe ich, dass es nicht in TypeScript selbst ist. Aber genau deswegen sind so Projekte wie TS Reset eigentlich gut. Weil du dir diese Dinge nachher selbst schreiben kannst. Und das ist nicht einmal schwierig. Also in meinem Workshop mache ich das auch.
Das ist ein Zehnzeiler, wo du das Interface vom Response-Buddy, mit einer anderen Methode überladest, die halt in der Anordnung der TypeScript-Methoden nachher die ist, die zieht und dann änderst du die Promise von Any auf Promise von Unknown und das Ding ist gestern und du hast ein Stück mehr Typsicherheit für das Ding.
Also das ist ein Dreizeiler und das ist sehr, sehr effektiv. Und drum sollte man das auch. Glaube ich, über eine dritte Party-Bibliothek gut am einfachsten geschehen, selber schreiben, machen. Ich würde hier tatsächlich ein bisschen bei dem Anfangsstatement widersprechen. Ja, man kann TypeScript so konfigurieren, dass es allen JavaScript-Code schluckt, aber du musst dafür halt ein paar Settings in der TS-Config entsprechend setzen und es wäre durchaus legitim gewesen, dafür auch noch mal ein Setting zu machen.
Absolut, ja. Und in default ist es ja nicht schwer zu lösen. Also so ein bisschen denke ich immer wieder, ich fände es schön, wenn das, was TS-Reset macht, einfach TS-Config-Settings wären. Weil das das deutlich, die Chance deutlich erhöht, dass man das verbreitert bekommt. Und selbst wenn es per Default unknown wäre, hält mich ja nichts davon ab, beim Handeln des Promise dann wiederum den Any als Parameter in das Land zu schreiben. Und dann funktioniert auch alles so, wie ich es mir gewünscht habe.
Also rauskommt man immer noch. Aber ist auch nur mi, mi, mi. Und jammer auf hohem Niveau. Es ist so cool, ich gehe gerade die Feature-Liste von TS Reset durch und das sind im Grunde meine Blog-Artikel, die ich rund um 2021 geschrieben habe. Aber ich glaube, ich habe deinen Blog lange nicht gelesen. Ich habe den übrigens früher sehr häufig beworben. Ja, da habe ich einiges gelesen.
Ja, da habe ich einiges gelesen. Und ich bin mir aber relativ sicher, das Design von TS Reset ist schöner als das von deinem Blog-Artikel dazu. Ich finde einfach immer wieder geil, wie gut diese Website von PS3. Das ist mein Blog schon lange nicht, Maxime. Der ist jetzt super fisch. Oh, ich dachte, ich wüsste die Adresse auswendig. Warte, ich hätte fatlog.eu gesagt. Ist das falsch?
Das müsste ich jetzt weiterleiten auf eudat.dev. Vielleicht ist die Domainer schon wieder weg. Nee, die ist noch da. Funktioniert noch. Ich war einfach nur zu blöd zu tippen. Also es leitet nicht weiter. Vielleicht willst du das machen, sondern ist jetzt ein Alias. Ja, das ist okay. Alias ist okay. Ich gebe ein feuchtes Irgendwas drauf auf Domains.
Das, was früher mal Suchmaschinenoptimierung war, das haben wir ja alles nicht mehr. Ja, genau. Da war ich einfach schon, Da war ich einfach schon fortschrittlich denkend, indem ich einfach drauf pfiffen habe. So. Dein letzter Blogartikel ist zu TypeScript. Das ist ja wunderschön. Das müssten wir eigentlich auch noch einbauen. Echt? Ist das wirklich ein Blogartikel?
Ah, nee, Writtenartikel sind TypeScript. Das war explizit die Kategorie TypeScript. Schön guten Morgens. Irgendwelche nicht offensichtlichen Anwendungsfälle, wo ihr Unknown rausholt? Außer jetzt, um es zu resetten? Oh ja. Oh ja, es gibt dieses wunderschöne Pattern von Type Assertions, wo ihr aber komplett Mumpitz macht, wo man eine Variable as unknown as any schreiben muss.
Ne, as any nicht, aber as unknown und dann as ein komplett invalider Typ. Was passiert da? Ganz kurz. Du gehst in dieser Menge auf die größere und noch auf eine andere kleinere zu gehen. Und wenn diese beiden Submengen halt nicht miteinander kompatibel sind, kriegst du einen Fehler. Du kannst ja von zum Beispiel einer Menge aus ein paar nur mal auf die größere gehen, absolut kein Problem. Und auch umgekehrt, das erlaubt die dir nicht.
Aber wenn du mit zwei komplett adjazenten Mengen zu tun hast, die keine Schnittmenge haben, erlaubt dir das TypeScript nicht. Was tust du? Du gehst zuerst auf die größere, any oder an, und da siehst du wieder, dass das eben die Supermenge ist und reduzierst dann auf eine andere. Das ist herrlich. Also das ist dann so dieser kaputte Use-Case von Unknown auf jeden Fall.
Und die Leute machen das mit dem Unknown, weil Any ja in ihrem statischen Code-Analyse-Tool verboten ist. Ja, es ist so schön, wie diese gesamte Theorie nachher mit pragmatischen Mitteln vorgeführt wird. Ich verstehe das aber auch und ich finde das auch gar nicht so schlecht. Also ich sage auch ständig, macht ihr das und seid euch nur bewusst, dass ihr später, wenn ihr irgendein Problem damit habt, diese Dinge wieder leicht finden können solltet.
Und da ist dieses S-Keyword herrlich dafür, weil du kannst einfach über Textsuche nach Lehrzeichen, S-Lehrzeichen suchen und du findest alle Stellen, wo du potenziell Probleme hast. Und das ist für mich ein sehr, sehr wertvoller Workflow. Mach mit dem Typsystem, was du willst. Dazu ist es so flexibel und dazu kannst du es so schön biegen und teilweise auch brechen.
Sei dir nur bewusst, dass wo du es brichst, dass du diese Dinge später wieder findest. Das ist ein viel, viel besserer Zugang, als wenn man sich an keine Ahnung, wie viele Linting-Rules oder Typescript-Typ-Kompatibilitäten hält. Also pragmatisch arbeiten, auf das Ziel hin arbeiten, aber sichtbar machen, was schief gehen kann.
Wenn man sich nämlich zu viel Korsett baut, mit irgendwie Any-radikal verbieten, dann führt das halt nur zu Workarounds. Und die sind dann halt eben schwieriger zu findende Versionen von dem, was man mit Any gemacht hätte. Ganz genau. Und darum, also Any ist ja für mich auch ein super Indikator. Ich liebe das.
Ich lese ja mehr Code, als wie ich schreibe nicht. und als wie, Entschuldigung, das ist eine sehr österreichische Aussage, ich lese mehr Code, als ich schreibe. Und ja. Und für mich sind solche Sachen irrsinnig gute Indikatoren. Wenn ich irgendwo Annie sehe, dann schaue ich da drauf und dann versuche ich zu verstehen, was da passiert.
Oder im besten Fall geben Leute eine sehr, sehr gute Dokumentation mit, was da passiert und warum sie auf Annie gegangen sind. Also das sind alles Indikatoren für Dinge, wo du mit einem Typsystem, das sowieso ja nur drangenagelt ist und versucht mitzulaufen mit etwas, was schon existiert und auch immer mit etwas mitlaufen wird, was schon existiert, sind genau die Dinge, wo du merkst, wo diese beiden Welten brechen.
Und nichts ist wertvoller als wie ein Zeichen, wo es bricht. Und das haben wir leider überall. Das haben wir jetzt, wenn man mit einem Backend redet oder auf User-Input wartest. Und das sind ja auch die spannendsten Dinge im Web, wenn es User-Input oder Backend-Bauten gibt. Sonst wäre es ja auf HD-JavaScript-Applikation.
Also unser Ziel war jetzt, dass wir eine 4-Stunden-Folge aufnehmen, oder? Nein, du musst mit das nur 5 Uhr aufhören. Wir können ja in mehreren Sessions eine Vier-Stunden-Folge aufnehmen. Eine ganze Staffel zu Annie. Ich dachte jetzt mehr an eine Trilogie, eine Star Wars. Das Anlone schlägt zurück. Darth Generic rückt an mit seinem Annie-Zerstörer.
Ich finde Annie ein super hilfreiches Mittel. Aber es gibt den Satz, die Dosis macht das Gift oder so. Also es gibt halt so Situationen, wo Annie wirklich hilfreich ist und wo es gut ist, dass wir es haben. Wo es notwendig ist, würde ich behaupten. Ja, aufgrund von Unzulhängigkeiten von Computern, aber ja, genau.
Oder menschlichen Gehirn. Und trotzdem sind so 90 Prozent der Fälle, wo ich Annie sehe, wenn nicht mehr, eigentlich Red Flags und da hat jemand sich keine Gedanken gemacht oder da hat jemand sich keine Gedanken gemacht. Also ich kann übrigens voll damit leben, wenn jemand den Kommentar in Annie verwendet und drüber schreibt, ich laff das nicht, ich weiß nicht, wie ich den korrekten Typescript schreiben soll.
Oder ich habe das probiert und nach 30 Zeilen Typings habe ich beschlossen, dass ich jetzt Annie dran schreibe, mich auch voll feindet. Aber sich keine Gedanken gemacht zu haben oder Faulheit sind so Sachen, wo ich echt allergisch auf Annie reagiere. Und die Grenze zwischen Faulheit und Pragmatismus wo es ist halt erstens schwammig und zweitens von Person zu Person unterschiedlich.
Ja, aber dann machst du das, was du halt in jeder verkeilgten Organisation machst und dann muss man halt irgendwie zu Papier bringen, in einen Kommentar schreiben oder so, warum da jetzt Annie dran steht. Also entweder irgendwie, wenn ich halt irgendwie so die Situation habe, wo das ist es jetzt nicht wert, gegen den Compiler zu Felde zu ziehen, das ist jetzt Annie, weil ich weiß, dass es funktioniert, dann schreibe ich das da halt eben dran.
Oder wenn ich irgendwie so Datenmutationen mache, die man nicht machen sollte, dann nenne ich meine Funktion immer unsafe dofu oder sowas, damit man halt irgendwie so nach unsafe grabben kann und dann halt irgendwie so die Funktionen findet, die halt für seltsame Mutationen sorgen. Aber es ist halt einfach so ein Feature, das unter Rechtfertigungsdruck steht.
Aber man kann ja eine Rechtfertigung drüber schreiben. Das kostet ja nichts. Und da finde ich durchaus so diese Idee ganz schön zu sagen, man verbietet halt any per statische Code-Analyse. Und deaktiviert das aber an den paar Stellen, wo man es deaktivieren will, mit einer weiteren Regel, die sagt, du erklärst bitte warum.
Und dann schreiben Leute halt Quatsch in den Kommentaren, hat das alles auch nichts gebracht, aber trotzdem, also ich finde es so, so, Den Default zu haben, wir verbieten das und erlauben Ausnahmen, finde ich besser, als zu sagen, macht mal, aber seid euch sicher, was ihr tut. Es kommt halt darauf an, wie prävalent in deiner Codebase hinterher die Ausnahmen sein werden. Wie bitte was?
Wie häufig die vorkommen, wie häufig du Ausnahmen brauchst. Prävalent war das Wort? Mhm. Dann schreibe ich mir gleich mal auf und google gleich. Okay, ja. Also, weil ich habe halt durchaus so Codebases, wo das halt irgendwie gar nicht vorkommt, weil ich halt einfach nicht Daten mutiere. Und dann gibt es halt welche, wo ich einfach so, man beginnt mit einem riesigen Array und das Endprodukt ist das gleiche Objekt, aber halt mit 7000 Modifikationen angefügt, dann müsste man halt, wenn man das mit TypeScript machen würde, was ja wahrscheinlich der erste Fehler wäre, halt in jeder Funktion sagen, ja, der Input ist eigentlich ein Any oder ein Array von Any oder irgendwie sowas, weil man halt ständig diese Dinger mutiert.
Und davon wird man es dann abhängig machen, ob das vielleicht ein sinnvolles Verbot-Dings ist oder so. Generell denke ich mir halt öfter mal bei Type-Checkern und Lintern und so. Kollege, ihr von der Blech-Fraktion wollt eigentlich mal so langsam mit eurer künstlichen Intelligenz um die Ecke kommen. Und du beschwerst dich jetzt darüber, dass ich hier irgendwie Wild-Schuhe habe mit einem offensichtlichen Break zwei Zeilen tiefer und du meckerst dir trotzdem.
Sag mal, was soll das denn? Ich habe jetzt gerade nachgeschaut, während Sie gesprochen haben, Sie war vor drei Monaten, ziemlich auf dem Tag genau vor drei Monaten, habe ich eine sehr lange Diskussion von fünf Leuten gelesen. Also bin ich in einem Slack-Trad dazugekommen. Da geht es darum, dass, ja, irgendwo gibt es halt einen Any-Wert und den darfst du nicht auf einer anderen Stelle.
Das ist ein irrsinnig komplizierter Type und Sie fragen, okay, wie können Sie dort jetzt am Workaround machen, damit der Linter dort nicht schreit und damit der Code dann funktioniert, weil der Code wäre an und für sich korrekt und braucht man andere Typen, braucht man ein anderes Interface, braucht man andere Funktionen, braucht man einen anderen Assignment-Vorgang.
Fünf Leute diskutieren, haben nachher sind ganz im Fuss gekommen, haben mich inkludiert und ich habe gesagt, trotz der Linting-Hole, die ist sowieso ein Scheiß. Und so einfach geht es. Das war die No-Unsafe-Assignment-Linting-Hole und in diesem speziellen Case war die halt sehr unangenehm. Man kann den Computer abschalten. Das geht.
Und ich denke, den Effort, den Leute dort einigesickt haben, haben wir fünf Leute dort für mehrere Stunden diskutiert und ist einfach das nicht wert, wenn jeder weiß, okay, das funktioniert so und sie wissen, dass es funktioniert und es ist getestet und hin und her. Und da reden wir ja zwischen Typsicherheit und Testcases.
Vor allem kommuniziert es mit einem Backend, da kriegst du sowieso dann irgendeine kaputte Backend-Message zurück, wenn der Typ nicht okay ist und den händeln sie ja sowieso im nächsten Fall. Also, ah, seht es halt so, dass euer Programm funktioniert und kümmert euch halt mal ein bisschen weniger darum, ob euer Puppenhaus aus DevTools richtig angestrichen ist. Meine Güte.
Ja, letztens hatte ich übrigens einen sehr ulkigen Fall, da ist leider der entsprechende Teilnehmer im Workshop nicht aufgetaucht. Der hatte explizit in die Agenda diktiert, ich möge doch bitte schön herausarbeiten, warum eine Type Assertion via irgendwas als irgendwas anderes schlechter lesbar sei als die Spitzklammer-Syntaxe.
Dann hat er einfach zwei komplett unterschiedliche Fälle. Gennet was? Wie? Nee, nee, nee. Du kannst ja irgendwie sagen, so Variable as any. Oder du kannst natürlich auch davor schreiben, Spitzklammer, Number, Spitzklammer. Also das, was wie ein Cast funktioniert. Ja, genau. Genau, wie so eine Typumwandlung. Ich halte zum Beispiel PHP ja auch nur halt eben mit Runden statt mit eckigen Klammern.
Und erst mal fand ich super, dass es Leute gibt, die das noch benutzen. Zweitens React-Inkompatibilität. natürlich auch super, wegen so JSX-Spitzklammern. Drittens erstmal so festgestellt, ah, guck mal, mein Syntax-Highlighter kann das gar nicht. Und dann halt erstmal auch festgestellt, so okay, die ganze Toolchain hat diesen Fall nie berücksichtigt, der Parser kann das gar nicht, weil das halt einfach so ein olles Teil ist aus irgendwie der ersten Version von TypeScript.
Und Wiederfindbarkeit, zwischen einem React-Code bis nach einer spitzen Klammer, wie er steppert, ne? Ja, das war ein Angular-Shop, deswegen war das da nicht. Leider war der Teilnehmer den ganzen Workshop nicht da, sodass ich ihn nie darauf festnageln konnte. Und der Rest halt halt nur sogar, ja, ja, der hat halt so seine originellen Meinungen.
Aus der Philosophie Sicht ja eine tolle Frage, da kann man ewig drüber diskutieren, weil es ist spannend, herrlich. Nee, komm, das ist einfach so ein Fall von, keine Ahnung, Eaps vs. Space, das ist doch genau das Gleiche. Es ist doch alles bloß hier Sonntagsgefriemel und das kann man besser finden oder nicht, aber am Ende geht es ja darum, was sagt das Ding denn aus?
Und keine Ahnung, wenn der komische Typ jetzt hier mein Boss gewesen wäre und er würde sagen, wieso muss man das schreiben, dann würde ich sagen, du bist komisch, ich schreibe das halt so, ist mir egal, Hauptsache, ich kann mich hier um die eigentlich wichtigen Dinge kümmern. Der Kiki seufzt schon die ganze Zeit, ich glaube, ihm liegt echt was am Herzen gerade.
Ich muss ja dazu sagen, dass ich eventuell in dieser Liste der Themen vorhin explizit das Thema Type Assertions aufgenommen habe und ich finde es schön, dass wir da jetzt aus Versehen hingekommen sind. Type Assertions und auch diese Spitzenklammern haben für mich ein Problem. Ich habe das Gefühl, dass EntwicklerInnen, die aus richtigen Programmiersprachen kommen, Entschuldigung, das musste sein, die Erwartung haben, dass das ein Typecast ist, weil es im ersten Moment sehr ähnlich aussieht und sich auch sehr ähnlich anfühlt.
Es aber was komplett anderes ist, nämlich es ist, lieber Compiler, du hast keine Ahnung, ich weiß es besser und falls ich mich doch irre, dann ist es meine Schuld, dass wir auf die Fresse fliegen. Ja, es ist so ein fundamentaler Unterschied. Es ist ein ähnlicher Syntax, aber es ist einfach ein komplett anderes Konzept, weil in den einen stehen halt einmal Bytes dahinter und das bedeutet, wenn du einfach eine so große Anzahl an Bytes in eine so große Anzahl steckst oder umgekehrt. Da gibt es halt einen Unterschied.
Und beim anderen sagst du einfach nur im Compiler, hey, ich glaube, das ist was anderes, wie du glaubst. Ja, und es ist ja auch, wenn du einen Typecast in der einen oder anderen anderen Sprache machst, dann kannst du ja auch plötzlich Methoden aufrufen auf diesem Ding, die eigentlich gar nicht darauf existierten.
Also wenn du irgendwie sagst, hier, ich habe einen User und ich castere den jetzt in einem Admin, dann kannst du die Methoden von Admin aufrufen. Das ist halt in TypeScript auch nicht der Fall. Und es wird ja auch nicht im Moment des Typecasts um die Ohren fliegen. Andere Programmiersprachen sagen dann zur Laufzeit, hey, dieser Typecast hier ist irgendwie kaputt, ich breche mal hier lieber ab, bevor du Quatsch machst.
Und da TypeScript zur Laufzeit weg ist, passiert das eben auch nicht. Also deswegen ist nämlich dieses AS ähnlich wie das ADDI so ein richtig gutes, so ein richtig hilfreiches Werkzeug, wo über 90 Prozent der Anwendungen, die ich davon gesehen habe, aber einfach nicht hätten sein dürfen. Backend-Kommunikation, ich verstehe euren Punkt, ich glaube, das ist dann halt auch wieder so eine Abwägung von Pragmatismus.
Also wenn ich jetzt eine Anwendung als Hobbyprojekt alleine im Keller schreibe, dann kann ich da auch gerne überall Annie an die Backend- Responses dran schreiben, das ist alles in Ordnung. Wenn ich jetzt Termin mit 200, Entwicklern an der gleichen Code-Basis arbeite, da will ich halt nicht, dass da überall Type-Assertions und Annies drinstehen, weil dann blicke ich irgendwie nicht mehr durch.
Dann kann ich TypeScript auch sein lassen, kann ich jetzt etwas übertrieben vielleicht sagen. Dann kann ich auch JS-Doc verwenden. Doch bist du schon sehr nah an der Lösung dran, vielleicht sollte man TypeScript doch einfach sein lassen. Das ist natürlich ein bisschen scherzhaft jetzt gemeint. Ich verstehe dich.
Bei mir nicht. Bei mir nicht. Es gibt halt da durchaus so Projekte, wo ich sage, da TypeScript dran zu dengeln, zieht einen Aufwand nach sich und einen Benefit an Typsicherheit. Wo das Verhältnis halt nicht gewahrt ist. Und dann sagt man lieber, holt mal Bier, dann machen wir es gleich in JavaScript.
Hat man halt mit einigen Sachen mehr Schmerzen, mit anderen Sachen weniger. Und man kann durchaus ein Szenario sich überlegen, wo man sagt, unterm Strich lohnt sich der TypeScript tatsächlich nicht. Wenn man zum Beispiel wirklich irgendwie ganz viel mit nackten Web Components macht und irgendwie alles irgendwie ein String ist, dann bringt es das halt eben nicht.
Dann kann man halt nur riesig viel Aufwand betreiben, um da irgendwie sich einem React-artigen Zustand anzunähern. Oder man kann sagen, da komme ich eh nicht hin. Machst du ein nacktes JavaScript, sparst du ja einen Compiler an der Toolstelle. Ich möchte noch ganz kurz auf etwas zugehen, was der Kiki jetzt gesagt hat. Ähm, Weil ich stimme dir ja sogar zu. Also ich stimme dir zu, dass wenn du jetzt 200 Leute in einem Projekt hast und du hast lauter Typer-Sersals da drinnen, dann hast du irgendein Problem.
Ich würde mal sagen, in den wenigsten Fällen ist das Problem die Typer-Sersals, sondern du hast wahrscheinlich ein organisatorisches Problem. Also warum gibt es diesen Divide zwischen Frontend und Backend, dass du hier überhaupt über Typen diskutieren musst? Oder sind die Dinge eh so nahe beieinander, dass die Leute, die diese Backend schreiben, eh wissen, was dort ankommt und du kannst eigentlich die Typ-Checks dort sparen.
Am schönsten ist immer, wenn du ein Node-Backend und ein JavaScript-Frontend hast und du einfach in der Mitte die Typen hast und du schickst auf der einen Seite das mit dem Typen raus und empfängst es auf der anderen Seite, brauchst du keinen weiteren Check machen, ob das stimmt oder nicht. Das garantiert dir ja dein eigener Code und deine eigenen Typ-Checks auf beide Seiten.
Und von dem her kommt dieses Überprüfen der Backend-Ergebnisse auch immer auf den Umstand an, wie du organisatorisch aufgestellt bist. Ich sage zum Beispiel bei uns in der Organisation, wir verwenden SORT ziemlich oft. Das ist so eine Pass-Not-Valitate-Bibliothek, die ist cool, die ist typsicher, die gibt super Ergebnisse und ich habe gesagt, die ist so schwer und macht so langsame Serverless-Functions, nutzt die wirklich nur, wenn du sie euch nicht auf das Backend verlassen könnt, mit dem ihr kommuniziert.
Und das machen sie jetzt auch nicht. Also überall, wo wir eine Drittparty haben, ist das Ding drinnen. Übrigens, wo wir eine First- oder Second-Party reden, nicht. An der Stelle würde ich einen kurzen Werbeeinschub für einen Podcast von vor einem Jahr ungefähr machen. Revision 639, Server-Client-Kommunikation mit TypeScript vom Working Graph Podcast, wo auch SOT erwähnt wird.
Und ich, ach und da kann man auch TS Reset vor, sehe ich gerade. Ich würde da einen Punkt zu der internen Kommunikation noch hinzufügen. Man sollte dann halt in irgendeiner Form früh genug mitbekommen, wenn das Backend-Mux zurückliefert. Also wenn das Backend plötzlich mit einer HTML-Seite als Fehlermeldung antwortet statt mit JSON, dann fliegt das JSON-Pass schon um die Ohren.
Aber es kann ja auch sein, dass es in der JSON-Response antwortet, wo irgendwie Success-False drinsteht. Und wenn dann aber mein Code annimmt, das funktioniert alles, dann ist es halt doof. Da mach zum Ersten mal richtige HTTP-Status-Codes. Das ist das erste Kommunikationsproblem, das du hast. Du darfst nicht ein Success reingeben in eine Information über den Success innerhalb von der Payload, sondern eine Information über den Success kommt über den Status-Code mit und dann wird das auch auf einer anderen Stelle abgefragt.
Das kannst du auch super überprüfen. Du kriegst in der Response diese Information mit. Noch bevor du dort Chasing aufhugst, also bevor du diesen schweren Weg des Passens des Ergebnisses angehst, kannst du schon überprüfen, ob das überhaupt sinnvoll war, was du kriegst oder nicht? Du musst es aber parsen. Also du musst halt den Status-Code prüfen.
Das ist so. Ja, genau, weil der sieht in Headers und dort chasen geht ja nur auf den Body. Ja, man kann sich jetzt, glaube ich, auch stundenlang darüber streiten, ob das eine Fehlentscheidung ist, wie Fetch das handhabt oder nicht. Ich kann aber nachvollziehen, dass Menschen die Erwartung haben, wenn ich einen HTTP-Request mache und das Then von dem Fetch, also das Promise Resolved und nicht Throwed, dass dann das HTTP-Request erfolgreich war.
Es ist ja auf eine gewisse Weise erfolgreich gewesen, weil du bist ja zum Server gekommen und hast dir im Worst Case da die Abfuhr eingefangen. Und das ist, glaube ich, ein Zustand, der zu unterscheiden ist zwischen, du befindest dich im Flugmodus. True und False ist halt nicht notwendigerweise so binär, wie man sich das vorstellt.
Ich bin da auf deiner Seite, aber trotzdem, ich kann nachvollziehen, dass Menschen diese Erwartung haben. Also jetzt mal ganz ehrlich, wie viele JavaScript-Anwendungen habt ihr gesehen, in denen nicht der HTTP-Status-Code im Fetch überprüft wird? Oder ich meine, Error-Händling in JavaScript ist ja sowieso irgendwie sehr stiefmöglich.
Du hast absolut recht, es ist aber keine Lösung jetzt zu sagen, wir werfen Errors in einer Programmiersprache, wo das Errorwerfen generell problematisch ist. Was man da macht ist, wenn man sich die Realität entsprechend vereinfacht, dann kann man sich dieser Programmiertechnik namens Abstraktion bedienen und dann läuft die Kiste.
Dann machst du einfach hier einen Rapper um Fetch, den kannst du dann sogar irgendwie Get nennen, dann ist das noch kürzer, drei Buchstaben. Und dann machst du da drin halt eben, wenn die Response irgendwie doof ist, dann schmeißt das Ding auch eine Rejection raus. Das ist total easy, alles zu lösen.
Aber so die Baseline, die im Browser wohnt, wie das Fetch, ist da schon mit einem anderen Maß zu messen. Das ist jetzt nicht zu 100% darauf ausgelegt, maximale Developer Convenience zu bieten, sondern das bildet erstmal ab, wie die Welt aussieht und die Welt sieht halt eben zwei unterschiedliche Möglichkeiten vor, ins Klo zu greifen, wenn du mit dem Server zu reden versuchst.
Und die müssen dann unterschieden werden. Mehr. Also die Primären sind Request verlässt deinen Computer nicht und Request verlässt deinen Computer und geht dann irgendwie vor die Hunde. Und dann kannst du den letzten Fall ja doch differenzieren anhand von HTTP-Status-Codes. Oder Dinge, die im Body stehen. Wenn man ein richtiger Entwickler ist, dann natürlich auch das, ja.
Also das Einzige, was ich sagen wollte, ist, auch bei einem internen Backend kann es halt mal sein, dass da Mumpids an Daten zurückkommen. Dann ist es schon schön, wenn die Anwendung so früh wie möglich dabei um die Ohren fliegt. Und ich glaube, da ist dann eine Frage von, nicht nur ist das Backend intern, sondern auch.
Wie viel Vertrauen habe ich in das Backend? Oh, ich hätte tatsächlich diese Überlegung, um noch einen weiteren Galaxy-Brain-Level-Gedanken zu ergänzen. Also wenn wir jetzt erstmal schon mal davon ausgehen, dass wir ein Backend haben und das ist mehr oder minder intern, aber ein getrenntes System von unserem TypeScript, wenn das so unsere grundsätzliche Ausgangslage ist, würde ich ja tatsächlich mal in Frage stellen, inwiefern überhaupt TypeScript ein Monolith ist.
Und ist es nicht vielmehr so, dass es sich bei dem, was wir als TypeScript wahrnehmen, mehr um so eine Wohngemeinschaft aus zwei Elementen handelt, wo einerseits YOLO JavaScript, alles kann, nichts muss existiert und eine andere, etwas seltsame, funktionale, statisch typisierte Sprache, die mit dem JavaScript zusammenarbeiten kann, aber wo trotzdem dieses Zweierteam nicht immer genau die gleiche Vorstellung davon haben muss, was die Realität ist.
Ich will sagen, haben wir nicht so, selbst in Abwesenheit eines Backends ein Zusammenspiel aus zwei getrennten Systemen, ohnehin an der Backe, indem wir halt JavaScript im Browser haben und das Typsystem und die haben irgendwie so grob die gleiche Richtung, in die sie gehen, aber die können genauso gut zwei unterschiedliche Meinungen haben, wie zwei Piloten, die im Cockpit sitzen und der eine meint nach links, der andere meint nach rechts.
Ich empfehle meinen Vortrag Lies with Hello Ourselves using Typescript, weil du kennst genau das. Ihr habt 15 bis 20 Zeilen Code geschrieben und ihr habt Typprobleme in jeder Zeile Code. Das ist also TypeScript kompiliert, TypeScript findet es super und das Programm crasht an jeder Zeile. Also das war meine Aufgabe und die Aufgabe ist nicht einmal so abwegig, also das ist jetzt nicht irgendwie ein...
Großartig konstruiertes Beispiel oder so, sondern dann geht es um einen Fetch Call, über das wir ja gerade reden, das halt einfach sämtliche Type Guards oder Type Checks auslässt, wenn es darum geht, mit dem Ergebnis zu arbeiten und du hast halt irgendwo eine Zeile drinnen, die keinen Sinn macht, aber die passieren kann und genau deswegen geht alles in die Luft und selbst wenn du die Ergebnisse richtig bekommst, brauchst du nur auf die große zweite Sprachstelle von TypeScript eingehen, nämlich, Mutability auf Referenzen und hast halt dann den Wiss benannt.
Du kannst ja Objekte in jede Funktion stecken, kannst den Typ innerhalb von dem Objekt typ-sicher komplett verändern und greifst nachher draußen auf Dinge zu, die nicht mehr stimmen und hast dann dort das Problem. Und das sind 15-Seine-Code oder 20 von mir aus, die brechen an jeder Stelle und das ist ein herrliches Problem, wo du alle Schwachstellen siehst, die halt aber tatsächlich in echten Code auftauchen.
Und deswegen sage ich 100%ig recht, du hast absolut recht, das stimmt. Oder du versuchst auf iterative Weise ein Objekt zusammenzubauen aus irgendeiner wie auch immer gearteten Datenquelle. Das geht halt nicht, weil halt eben diese zwei WG-Bewohner halt eben nicht ein 100% deckungsgleiches Weltbild von dem haben, was man macht und was geht und welche Operationen zu welchen Ergebnissen führen.
So, und dann ist halt die Frage, dass mit dem Backend eigentlich das kleinere Problem, also ja, da fällt das dann auf und man ist halt meistens so, wie Stefan schon sagte, aufgrund den Lügen, die man sich gerne so einredet. Der Meinung, dass irgendwie unser WG-Mitbewohner und wir die exakt gleiche Perspektive auf die Welt haben, damit kann man halt wirklich relativ weit kommen, aber irgendwann stellt man fest, ach wir beide dachten, wir haben noch Spaghetti da und jetzt gibt es keine mehr. Pech.
Der ganze Kack ist halt immer komplizierter, als man so meint. Und das ist ja allgemein auch einfach so eine Kiste bei TypeScript, wie oft man da dann in Rabbit-Holes einsteigt und es einfach unfassbar kompliziert wird. Und da dann einfach mal Annie dran schreiben, ist halt schon manchmal sinnvoll. Und wenn Unknown ist auch, tut das noch besser. Und damit haben wir die Kurve zurück zum Anfang.
Super, danke, dass du wieder zurückgefunden hast. Ich war mir jetzt nicht sicher, wie man dort hinkommt. Aber ich glaube, einer geht noch, oder? Ich wollte noch meinen Unknown-Use-Case eigentlich noch einwerfen. Ich mache gleich wieder eine Überleitung. Ich gebe Mühe. Ja, alles klar, Herr Delling. Ich zähle auf Sie. Also, ich war heute beim Friseur, deswegen mache ich nicht mehr ganz so den Netzer.
Also, was ich sagen wollte war Folgendes. Stellt euch vor, ihr baut eine JavaScript-Library mit natürlich TypeScript und eure Nutzerschaft besteht halt zur Hälfte aus TypeScript-Leuten und zur Hälfte aus JavaScript-Leuten, die das halt ohne den Benefit von so einem Typ-Checker benutzen. Mag es ja geben.
General Public ist so eure Zielgruppe. Und jetzt baut ihr halt so eure Funktionen, die eure Library exportiert. Die nennen wir Foo. Und das ist einfach so, dass der eine einzige Public Export eurer Library. Wie gestaltet ihr die Typ-Annotation von dieser Funktion? Also, es gibt einen erwarteten Input-Typen, es gibt einen erwarteten Output-Typen und es ist halt so eine Library mit halt so reiner Funktion als Public-Facing-Consumable und ihr habt halt einen Haufen interne Funktionen, in die ihr halt eben dann die Inputs und so weiter reinsteckt, eine Funktionsverschachtelung.
Sagt ihr in der Typsignatur eurer Funktion, jo, ich kriege hier einen Input und der Input ist vom Typ bla. Oder sagt ihr, dieser Input ist vom Typ unknown. Oder sagt ihr, irgendwas anderes. Nee, du hast recht. Wir sind hier eigentlich genau bei der Situation von gerade auch. Wenn diese Library von JavaScript entwickelnden Personen verwendet werden soll, dann ist der Wert ja unknown.
Theoretisch könnte es ja sein, dass da irgendwer in irgendwelchen Blödsinn reinsteckt. Klar, kann passieren. Es ist genau, naja, es kommt davon, also die meisten Bibliotheken sind so, dass eigentlich jeder darauf pfeift, ob der Impot jetzt richtig ist oder nicht und du bist schuld, wenn du das falsch verwendest.
Das ist ja nicht unser Anspruch. Wir wollen hier was bombensicheres machen. Stell dir vor, Stefan, du baust irgendwas, was wirklich fundamental ist, was am Ende alle Leute in deiner gewaltigen Company benutzen werden. Da willst du ja irgendwie schon sicherstellen, dass du irgendwie jetzt nicht, wie so gewisse irgendwelche Rassenbugs am Ende in die Nachricht...
Ich möchte natürlich die gesamte Probleme auf die Anwender und Anwenderinnen geben und nicht auf mich. Natürlich ist das dann ein Level-Auch-Problem. Ja, ja. Aber ihr versteht, worauf ich mich ausschöpfe. Aber ich verstehe dich nicht. Es kommt darauf, was der Anspruch ist. Tatsächlich kann... Wir sind ja da genau wieder an dieser Grenze. Ich würde sogar eher sagen.
Es geht mir weniger darum, ob das JavaScript-EntwicklerInnen oder EntwicklerInnen sind, sondern es geht mir darum, an welcher Stelle setze ich diese Funktion ein, ist die basierend auf Anwender-Input, nicht EntwicklerInput oder EntwicklerInnen-Input, sondern auf Anwender oder AnwenderInnen-Input. Dann gestalte ich das so offen, dass ich natürlich mit dem Ergebnis oder mit dem Input zuerst etwas tun muss und den validieren muss und den überprüfen muss, bevor ich den weiterschicke.
Also bin ich da an dieser Grenze, wo das Typsystem, das ich mir aufbaue. Nicht bricht, sondern die Grenze überschreitet zu einem anderen System, zu einem anderen Input, was auch immer, oder nicht. Wenn das nur ein anderes Team ist, dann sage ich einmal, okay, ich rede dich einmal zusammen, bevor ich sage, okay, ich mache dort jetzt irgendwelche Safeguards innerhalb von meinem Code und habe den Typen anon.
Weil tatsächlich ist es so, auch wenn der Typ anon ist, das ist ja nur ein Anspruch, eine Erwartungshaltung von mir und nicht die Erwartungshaltung von dem Anwender oder der Anwenderin. Und da kann ich die Erwartungshaltung entsprechend ändern. Wenn es aber so ist, dass ich nicht kontrollieren kann, was dort reingibt und auch den Leuten, die damit umgehen, nicht das Richtige beibringen kann, weil es zum Beispiel über Formular passiert oder sonst irgendwas, dann gehe ich von anderen aus.
Aber du hast vorhin selber ja durchaus angemerkt, dass so SOT bei jedem HTTP-Request ein bisschen Performance kosten kann. Letztendlich ist das, was du gerade vorschlägst, dass React in jedem Funktionsaufruf, in den Dinge reingegeben werden, die ein Nutzer von React übergibt, prüfen sollte, ob das den korrekten Typen hat, oder?
Also bin ich ein Entwickler, der mit React arbeitet, oder bin ich ein Nutzer, der eine React-Applikation verwendet? Also du und ich. Nein, also mir geht es dort tatsächlich um die Anwenderinnen und Anwender der Applikation, nicht die Entwicklerinnen und Entwickler, die damit arbeiten. Dann habe ich dich mit verstanden. Dann brauchen wir aber auch nicht anderen reinschreiben in dem Fall, Und da geht es eben genau um diese Erwartungshaltung, die ich von diesem Interface habe.
Also dann schreibe ich dort einen anderen rein, weil ich tatsächlich nicht sagen kann, was dort reinkommt. Wenn ich das anderen Leuten gebe, die damit entwickeln, dann ist meine Erwartungshaltung, dass sie zumindest die Dokumentation lesen und wissen, was dort reinstecken soll. Okay. Oder meine Erwartungshaltung ist, dass wenn ich dort den richtigen Typ reingebe, dass den die IDE dieser Leute zumindest den Typen aufgreift und damit was macht, auch wenn sie schon nichts damit machen.
Naja, aber guck mal, das würde ja zum Beispiel nicht passieren, wenn dein Input-Parameter unknown wäre, weil dann könnte ja die IDE über diesen Typen nichts sagen. Genau. Deswegen mach da nicht unknown rein. Deswegen mach ich nicht unknown rein. Okay. Wisst ihr, was ich mache in der Situation? Die Idee der JavaScript-Entwickler schreit ja dann trotzdem nicht.
Egal, ob du unknown drin ist oder der Typ, aber zumindest kriegst du autocomplete. Ja, ja, das ist ja auch schon mal was wert. Aber wenn du unknown machst, geht halt die autocompletion flöten und damit hast du ja im Prinzip das kaputt, was du ja versuchst zu erzielen. Weißt du, was ich mache? Ich mache beides.
Ich mache ein Overload. Ich mache in solchen Fällen immer eine Funktion, die in Sicht als eigenen Typ-Parameter, als Implementierungssignatur unknown hat, damit ich in der Funktion gezwungen bin, das Ding per Type-Checking zu überprüfen, ob es auch wirklich passt. Und dann mache ich ein Overload drüber mit dem Typen, von dem ich hoffe, dass ich ihn kriege, mit der Intention, dass das die Autocompletion aktiviert, bei denen, die halt eine Autocompletion haben.
Ich aber trotzdem selber in der Innensicht gezwungen bin, paranoid zu sein, weil in der Implementierungsperspektive der Typ ja unknown ist. Das heißt, nach außen sage ich, gib mir Fu. Nach innen sage ich, ich glaube dir aber nicht und zwinge mich dadurch, das zu machen. Das ist eine relativ einfache Maßnahme, um halt so diese Kontaktpunkte zwischen den Systemen wirklich festzunageln, weil wir ja vorhin schon sehr wortreich herausgearbeitet haben, das ist ja da, wo es meistens knallt.
Und das ist ein Einzeiler, mit dem man viel besser sicherstellen kann, dass das passiert. Man kann das relativ einfach im Code-Review auch sehen, dass das gemacht wird. Die Public Functions müssen halt dieses Feature haben und das ist entweder da oder nicht da. Und wenn ich jetzt nicht gerade so irre Performance-Constraints habe mit irgendwie Serverless-Functions, sondern einfach nur sage, Das ist eine Library und die soll halt super stabil sein.
Also für mich ist es immer kontextabhängig. Also wenn die Teams anders nicht miteinander arbeiten können, ja, in Gottes Namen, dann mache ich das halt auch so nicht. Ist okay. Und wenn das der Anspruch ist, ist das auf jeden Fall ein valides Mittel, das zu tun. Overloads sind sowieso schwer unterschätzt. Das ist eine richtig coole Methode, um Typen zu decken in Fibscript. Großer Fan davon.
Ja, und natürlich hinterher beim Debugging absolute Maßnahmen zur Sicherung des Arbeitsplatzes. Auch nicht unwichtig. Überfordern auch grundsätzlich LLMs. Bitte was? Kiki zuerst. Überfordern auch grundsätzlich LLMs, weil die Fehlermeldung so lange ist, dass der Kontext zu groß ist. Also insofern ist Richard und Zintroff, das stimmt schon.
Ihr vergeschlagen, wir machen noch einen. Einen machen wir noch, komm. Wie lange kann es schon dauern? Stefan, lass würfeln. 58, das haben wir wieder in TypeScript Oh no, okay, das ist meine Schwachstelle, Peter, da musstest du reden, Wir sind bei Decorators Decorators, ja, was soll ich dazu sagen, wir sind ja sowieso hier mehr oder minder der OOP-Hater-Club also warum würde jemals jemand von uns an eine Klasse irgendwie eine Annotation mit einem Ad-Zeichen dran schreiben, oder ein Framework gestalten, das nur auf Decorators aufbaut Ja, ja, also habe ich alles schon gemacht, finde ich auch super, funktioniert voll Super verwende ich jeden Tag, ist prima, ist halt nicht vergnügungssteuerpflichtig.
Weil das mit TypeScript halt wirklich, also das ist, das ist hart. Ich bin mir noch nicht sicher, wo hier jetzt gerade Sarkasmus-Ironie sonst was und wo hier echte Aussagen drinstecken. Du, das ist alles wahr. Ich befinde mich da in einem quantenmechanischen Überlagerungszustand zwischen das ist Kack, aber ich mach's trotzdem.
Hör mal, du hast ja auch mal Webentwicklung gemacht früher. Du kennst das doch. Ja, also ich meine, es ist voll super für sehr wenige Use Cases. Und für diese Use Cases, und da bin ich natürlich wieder normalerweise bei meinen Web Components, ist das klasse, weil wenn ich da E-Klassen benutzen muss und ich da halt irgendwie so ständig wiederverwendbare Plugin-Logik habe, weil sich Attribute, die Strings sind, immer gleich verhalten, ist es ganz gut, wenn ich einfach an Klassenfelder dran klatschen kann, du bist ein String.
Wenn ich an eine Klasse dran klatschen kann, du bist ein Element. Wenn ich an eine Methode dran klatschen kann, wenn Attribute erendern, musst du dich auslösen. Das ist schon ganz nett. Es ist halt nur wirklich brutal, was so die Syntax so angeht. Ich muss ja sagen, dass ich irgendwie, also ich mag Decorators, Entschuldigung, aber ich bin ein bisschen traurig darüber, was da in TypeScript oder JavaScript draus geworden ist.
Also in meiner Welt heißen ja einfach Annotationen. Und als Annotation finde ich die eine schöne Idee. Decorator finde ich ein bisschen schwierig. Also wenn man Metadaten an Dinge dran packt, dafür finde ich die wirklich toll. In dem Moment, wo die unfassbar verändern, was da drunter steht, finde ich es immer ein bisschen schwierig.
Und dass das in TypeScript oder JavaScript geht, total tolles Werkzeug, aber... Aber mein Letztand sagt ja, es geht eh noch nicht, oder? Also es ist eh... Naja, naja, naja, was heißt ja wieder, es geht. Das ist jetzt schon wieder irgendwie so, das hört sich ja schon wieder so an, als würden wir wieder hier in den Reich des Binären abrutschen.
Aber meine Herren, die Realität ist ja viel komplizierter als das. Weil ich meine, die JavaScript-Decorators werden in keiner JavaScript-Engine unterstützt. Da muss man dann schon irgendwie einen Transpiler rausholen, wie Babel oder eben TypeScript. Und dieses Feature-Sidekick, vor dem es dir so graust von wegen, oh nein, die verändern alles. Kann ich dich beruhigen, nix davon, akzeptiere TypeScript.
Das ist ja aber das nächste Problem für mich mit Decorator. Wir sind ja gerade hier im Themenblock TypeScript. Dass es zwei verschiedene und inkompatible Implementierungen gibt, ist richtig, oder? Es gibt irgendwie, du weißt da Dinge. Es gibt in TypeScript, wenn man da die Experimental Decorators aktiviert, dann aktivieren die eine Legacy-Version von Decorators, die sie implementiert haben, bevor das Ding fertig und abgesegnet war.
Also die Quintessenz ist, wenn man in TypeScript Decorators den richtig haben will, muss man Decorators nicht aktivieren. Wenn man Decorators aktiviert, kriegt man den alten Schrott. Wenn man Decorators deaktiviert, kriegt man Decorators. Obviously. Ich hasse einfach alles. Deswegen funktioniert das Zwischenums 3 so gut. Ich glaube, wir haben den gleichen Level Abneigung gegen Technologie entwickelt.
Das ist schon ein Eindruck, wie unsere Industrie sowas werden konnte. Technologie ist super. Es ist nur die anderen sind das Problem. Ah, schön. Experimental Decorators, true. Ja, schön. Also sagst du, das will ich mal auf Falls stellen? Das willst du auf Falls haben, dann kriegst du die richtigen Decorators.
Ab Modulo, du verwendest irgendwelche Libraries, die aus Legacy-Gründen den alten Kram supporten. Oder du verwendest von denen halt eh nicht so viel, weil ich meine, wie gesagt, mit TypeScript ist das mit den Use Cases echt ein bisschen schwierig, weil Decorators können in JavaScript zwar die Typen von den dekorierten Elementen verändern.
Die können irgendwie, wenn eine Methode irgendwie Strings zurückgibt, können die das Ergebnis von dieser Methode irgendwie durch die Number-Funktion jagen und dann Zahlen rausgeben. Und diese Änderung der Signatur der Klasse ist Typescript halt nicht beizubringen. Es geht nicht. Man kann keinen Typ formulieren, der das macht.
Typescript glaubt halt immer, wenn sich eine Klassendeklaration anschaut, die Klasse, so wie sie geschrieben steht, mit ihren ganzen Members, wie sie da geschrieben stehen, entspricht der Wahrheit. Und wenn man da anfängt, irgendwie fancy zu werden, indem man da Decorators raufklatscht oder irgendwie im Constructor Dinge macht, die man nicht machen sollte, dann weigert sich Typescript, das zur Kenntnis zu nehmen und es ist halt nur konsequent.
Ich habe noch eine Folgefrage. Dieses Emit-Decorator-Metadata funktioniert wahrscheinlich nur mit den Experimental-Decoratoren? Genau. Das gibt dann Decorator-Metadata aus, was nicht zu verwechseln ist mit Decorator-Metadata, was was komplett anderes ist. Die Decorator-Metadata von den Experimental-Decorators sind tatsächlich Metadaten, die im TypeScript-Code vom TypeScript-Compiler emittiert werden, um dann irgendwelchen Runtime-Metaprogrammierungskrempel zu ermöglichen, den TypeScript lieber wieder in die Dose stecken.
Wollen würde und so tun würde, als wäre das nicht passiert. Aber geht halt nicht bei Legacy. Und Decorator Metadata ist tatsächlich ein Werkzeug von den Schneider-Decorators, mit dem Decorators miteinander reden können. Also ich habe irgendwie einen Klassen-Decorator und in der Klasse habe ich Methoden, auf die klatsche ich einen anderen Decorator und diese beiden unterschiedlichen Decorators sollten miteinander reden können, weil sie auf der gleichen Klasse rumhacken und mit Decorator Metadata geht genau das.
Hat heißt also genau gleich und hat nichts miteinander zu tun, deswegen ist es Jahr wieder Web-Entwicklung, kennt man ja. Passt macht keine Integres und so. Wir enden mit einem schönen, also irgendwie mit etwas Freudigem. Und dann kommst du wieder um die Ecke mit der Realität. Ja, ich dachte, ich paste mal hier auch was in den Chat.
Das ist ja hier meine Decorator-Library für Web-Components. Ich sehe einfach nur Raute 443. Also das heißt, ich gucke mir jetzt eine Datei mit 443 Zeilen an. Ja, mehr. Das Schöne ist, ich habe... Das ist kompilierter Code, oder? Nein, nein, nein, nein. Du sagst ja immer, du bist kein Entwickler. Ich erinnere mich.
Erstens das und zum anderen habe ich auch wirklich bewusst gesagt, prima, ich sitze mit meiner ersten Covid-Infektion zu Hause und bin nur so halb da. Das ist genau der richtige Zeitpunkt, um sich Decorators drauf zu schaffen. So war das damals. Und seitdem habe ich diesen Code auch nicht mehr angefasst, weil er funktioniert natürlich offensichtlich.
Es ist halt mit der Lesbarkeit so ein bisschen so ein Ding. Und das ist halt so das zweite Problem mit Decorators und TypeScript. Die Domäne, mit der man da halt eben arbeitet, ist halt teilweise extrem Meta, weil man halt irgendwelche, sagen wir mal, Metaprogrammierung ja macht mit irgendwelchen High-Level-Konstrukten wie Klassen und Methoden und mit denen ja auch Metagramm macht, den man dann ja auch auf Typebene irgendwie nachvollziehbar machen muss.
Weil ich meine, selbst wenn diese Dinger tatsächlich nicht, diese Decorators nicht den Typ von etwas verändern können, müssen die ja zumindest in sich stimmig sein und verschiedene Signaturen supporten und so blödsinn. Und das führt dann halt eben zum hier sichtbaren Klammerinfarkt. Für all diejenigen, die jetzt nicht im Nachhinein auf GitHub nachschauen wollen, Peter hatte offensichtlich 13 Monate lang Covid, weil die Änderungen dieser Datei erstreckten sich über 13 Monate und wie wir wissen, war das alles während deiner einen Covid-Infektion.
Der letzte Kommentar ist übrigens, die letzte Comment-Message ist, remove comments. Den werden To-Do-Kommentare ohne irgendwas anderes daran zu ändern. Das freut mich sehr. Naja, das Problem ist halt eben, ich meine, niemand weiß das besser als so Menschen wie ihr, die ihr ja arbeitet an großen alten Software-Systemen.
Egal, wie lange man rumrefactort und egal, was man alles so macht, eine Software kann nie ihrer initialen Entstehungsgeschichte und ihrer initialen Idee entkommen. Das ist halt einfach dann irgendwann in der DNA drin und da kannst du so oft Haare schneiden, wie du willst. Am Ende ist da immer genau der gleiche Fettklumpen drunter, an dem das initial gesprossen ist. Und das ist mit diesen Decorators genauso.
Es ist halt leider irgendwie nützlich, deswegen muss ich es weiter benutzen. Aber weil es halt eben einfach entstanden ist im buchstäblichen Fieberwahn, ist das halt strukturell immer noch der schiere Fieberwahn und wird das immer so bleiben und ich habe auch keine Intention, das zu ändern, weil es funktioniert halt, es ist fertig.
Abgesehen davon, dass zu viele Kommentare drin sind, das beschwört ja die Gefahr der Lesbarkeit herauf, das wollen wir ja nicht. Und du hast eben so schön diese Frage mit komischen Use Cases von unknown. Ich habe einen komischen, vielleicht komischen Use Case von Dekoratoren und das absurde, ich bin mir nicht mehr sicher, ob es funktioniert hat oder nicht.
Ich weiß, dass ich das mal versucht habe in der Anwendung einzubauen, ich weiß nicht, ob es funktioniert hat und du wirst gleich erklären können, ob es geklappt hat oder nicht. Im richtigen Programmiersprachen gibt ja sowas wie so ein Type-of, nur dass es halt funktioniert. Das heißt, man kann auch prüfen, implementiert ein Objekt ein Interface zur Laufzeit.
Das ist was, was in TypeScript offensichtlich nicht funktioniert, weil das Interface zur Laufzeit nicht mehr da ist. Und ich meine, dass ich mir ein Workaround gefrickelt habe, dass ich einen Dekorator gebaut habe. Der nur auf Klassen, die dieses Interface erfüllen, angewendet werden kann und dann die Metadaten geschrieben habe, hier ist es drauf und dann einen Typeguard gebaut habe, der entsprechend auf das Interface narrowed und zur Laufzeit auch prüft, ob es funktioniert.
Bist du das ein oder hat das geklappt? Ja, okay. Es ist plausibel. Also was du natürlich machen kannst, Die Frage ist jetzt natürlich, was sozusagen dein Sprachmittel war, um das Implementieren dieses Interfaces zu checken. Ich glaube, ich meine, dass ich in irgendwelchen Meta dann oder in einem Symbol rumgehampelt habe.
Also irgendwas auch nicht so ganz Schönes habe ich da drin gemacht. Nee, die Frage ist, wenn du in deinem Brotcode drin bist und du willst jetzt irgendwie fragen, implementiert Objekt X das Interface Y? Was schreibst du, um diese Frage zu formulieren? Ich habe eine Funktion, die das für mich prüft. Und dann mache ich so ein If drumherum. Das ist so eine Kontrollstruktur, die viele Programmiersprachen unterstützen.
Okay, ja, nee, das kann man so machen. Ich dachte, jetzt machst du irgendwie so Kram wie Instance-Off oder so? Das geht ja dann in diesem JavaScript-Type-Script nicht. Mit einem Interface. Natürlich geht das. Mit einem Interface? Ja. Also nicht mit einem Interface, aber mit Instance-Off. Ich kann halt nicht Instance-Off-Interface-Name machen.
Du kannst nicht Instance-of-Interface-Name machen, aber du kannst ja Instance-of überladen und du kannst dann ja in die Überladung reinschreiben, was du sozusagen gelten lassen willst als Interface. Du kannst ja sozusagen dein Ducktyping formalisieren und so deine Klasse einbauen, dass Instance-of dieses Ducktyping ansteuert und du halt eben nicht random Funktionen mit if verwenden musst.
Das Problem ist, dass ich Instance auch nicht beim Interface überschreiben kann. Und ja, was gibt zu Recht, keine Mehrfachvererbung unterstützt und ich an der Stelle mehrere Interfaces verwenden wollte auf einer Klasse. Weißt du, das Problem ist, es gibt Vererbung konzeptionell und es gibt Vererbung, wie es tatsächlich dann mechanisch implementiert ist.
Und natürlich kannst du konzeptionelle Mehrfachvererbung herstellen. Du kannst es halt nicht mit den Vererbungsmechaniken von JavaScript herstellen. Wollte ich auch nicht. Ich wollte ja nur prüfen, man hätte halt auch prüfen können, gibt es da eine Funktion? Und das wäre eigentlich schon fast ausreichend, aber dann ist das nicht so typsicher.
Ja, aber was du halt tatsächlich gemacht hast, wahrscheinlich wenn du so eine Prüffunktion hast, das könnte ja tatsächlich einfach eine stinknormale Typeguard-Funktion sein. Genau, das war auch ein Typeguard, aber der muss halt irgendwo drauf prüfen, ob das gegeben ist. Und ich will halt nicht prüfen, gibt es da eine Funktion, die folgende Parameter entgegen nimmt? Ja.
Bisschen aufwendig. Genau. Du kannst sowas halt generisch gestalten und man könnte es theoretisch mithilfe eines Decorators Factory-Function-mäßig an eine Klasse dran tackern. Das einzige Problem ist, mit den Standard-Decorators wird TypeScript das halt nicht nachvollziehen können. Weil du ja den Typ der Klasse erweiterst, du machst ja sozusagen über einen Mechanismus, der nicht A Extens B ist, faktisch einen Subtyp aus der Klasse, die du dekorierst und das checkt er halt eben nicht.
Das besagte Projekt nutzt NestJS und NestJS braucht Experimental Decorators, wenn ich es richtig sehe. Insofern, ja, wird es das gewesen sein. Ich habe halt in letzter Zeit sehr viel Spaß damit gehabt, einfach Instance-Off zu meinem Sklaven zu machen, indem ich halt festgestellt habe, aber warte mal, es gibt ja dieses wunderbare Well-Known-Symbol namens hasInstance, das du auf einer Klasse implementieren kannst.
Und das ist eine statische Methode, die gibt True oder False zurück, kriegt als Parameter ein Objekt, ein anderes Objekt übergeben. Und das ist letztlich die Runtime-Implementierung von Instance-Off, wenn vorhanden. Da kannst du also wirklich hingehen und kannst sagen, A, Instance of Klasse B und dann kannst du das Ding dazu bringen, True zu sagen, auch wenn die beiden Dinger nichts miteinander zu tun haben.
Da weiß ich jetzt natürlich nicht, wie gut TypeScript das nachvollziehen kann. Ich kann auf jeden Fall nachvollziehen, wenn jemand deine Gedanken nicht nachvollziehen kann. Das müsst ihr mal ausprobieren, das klingt eigentlich echt interessant. Ja, ich hatte letztens den wunderbaren Use Case, wo das tatsächlich gebraucht wurde.
Ich hatte da Kundschaft, die ließ sich von mir beraten und die hatte ihr Bild im Bildprozess so mittelgut im Griff. Hatte so das Problem, die haben halt so ihre Library gebaut mit halt so lauter kleinen Helferfunktionen und dann gab es halt irgendwelches Software auf mittlerer Ebene und die haben das alles included und dann haben die auch die Dinge teilweise wieder reexportiert.
Lange Rede, kurzer Sinn, durch das Bundling gab es am Ende sieben verschiedene Instanzen der Bad Request Error-Klasse und man konnte halt eben dann in die Situation kommen, dass irgendwie Bad Request Error links flog, Bad Request Error rechts flog und wenn man dann gesagt hat, ist dieser Bad Request Error ein Instance of Bad Request Error, kam immer false raus, weil der Constructor, gegen den man das gecheckt hat, dann die dritte Instanz war.
Weil das halt einfach so Bundle-Duplikation war. Und das war halt voll super zu lösen, indem man tatsächlich Folgendes gemacht hat, also ich habe natürlich nicht irgendwie dein Bildsystem repariert, weil das wäre ja irgendwie, an der Ursache das Problem haben, statt irgendwie an den Symptomen rumzudoktoren.
Hab ich gesagt, wenn ihr einfach alles so lassen wollt, wie es ist, aber ihr halt wollt, dass Instance-Off diese unterschiedlichen Bad Request-Errors anerkennt, sozusagen, dann geht's eben hin, nehmt Symbol.for, um zum Anfang zurückzukommen und sagt einfach, auf euren diversen Bad Request-Errors steckt überall so ein Symbol mit halt irgendwie einem definierten Key heraufbeschworen, wo True hintersteckt und ihr überladet euer Instance-Off so, dass das Ding bei dem anderen Objekt einfach nur guckt, ob hinter diesem Symbol ein True wohnt und wenn ja, gibt es True zurück.
Und ich erinnere mich, dass ich diese Geschichte in deinem Workshop schon gehört habe und dass ich spätestens seitdem das mit dem Symbol vor mir hätte merken können, aber habe ich ja nicht. Tja, ich muss wohl wirklich nochmal demnächst bei euch vorbeikommen und dafür sorgen, dass das wirklich genau bei dir eingeschärft wird.
Kurze Antwort zu dem Thema Checked, TypeScript has instance? Natürlich. Weil TypeScript sagt ja nichts anderes. Also TypeScript gibt ja keinen Fehler, wenn du ein Instance-Off-Ding machst. Sondern TypeScript sagt ja nur im nächsten Schritt, ja passt, du hast einen Instance-Off-Check gemacht. Also ist das jetzt Instance-Off, was auch immer du für einen Typ checken willst.
Ob das jetzt stimmt oder nicht, seid ihr hingesteckt. Aber dem Typ-System nach entspricht es auch. Ja, und ich muss natürlich dann natürlich unter dem Aspekt auch meine Einschränkung von gerade zurücknehmen. Natürlich kannst du mit dem Decorator dieses HasInstance da drauf tackern. Du rufst es ja nicht direkt auf. Dass du den Typ der Klasse nicht änderst, ist ja egal.
Also es klingt extrem plausibel, was du erzählt hast. Das hast du wahrscheinlich wirklich so gelöst. Ich glaube nicht mit dem HasInstance, weil nochmal, das würde mit dem Interface nicht funktionieren. Ja gut, aber dann... Aber dann muss ich ganz kurz sagen, es gibt eben Compile-Time-Welt und Run-Time-Welt und TypeScript ist keine Run-Time-Welt. Und soll es auch nie sein.
Ich bin da manchmal traurig drüber, aber ja. Ich nie, auch egal. Du machst einfach eine Variable namens Instance und leitest da den Typ von her. Und dann hast du ja was? Dann hast du ja eine stoffliche Repräsentation. Die nennen wir bitte Dollar-Dollar-Type-Off. Damit sind wir wieder beim Anfang. Wunderschön. Jetzt sind wir wirklich full circle gekommen und haben ganze vier Einträge in unserem Glücksrat geschafft.
Ich bin sehr stolz auf uns. Nach zwei Stunden Aufnahmezeit. Meine Güte, ey. Da müssen andere Leute echt viele Meetings für kloppen, um so wenige Punkte in der Zeit fertig zu kriegen. Du hast recht. Und ich würde gerne wissen, wir machen das ja vor allem jetzt in dieser Dreierrunde, weil es ja das letzte Mal so gut funktioniert hat, wo wir über React so ausgekaut haben.
Entschuldigung, mir fällt nur das österreichische Schein, wo wir ein bisschen süffisanter darüber diskutiert haben, über dieses Thema. Und wir haben sehr, sehr viel gutes Feedback bekommen. Also ich bin sehr happy über das positive Feedback, aber auch zu den Diskussionen, die noch entstanden sind, das ist richtig cool gewesen. Sehr, sehr happy.
Und deswegen habe ich gesagt, passt, wir machen das gleich in einer weiteren Runde Glücksrad als der Kapo. Und persönlich würde ich gerne echt nochmal in dieser Runde über ähnliche Themen reden. Mir macht das irrsinnig viel Spaß, aber ich würde vor allem gerne von den Leuten draußen hören, ob sie das ähnlich so sehen.
Wenn ja, dann bitte wieder auf die gleichen Wege kommunizieren mit uns. Speziell, wenn ihr nicht in React oder TypeScript primär zu Hause seid. Also manchmal ist das ja so, dass man sich Content auch einfach reinzieht, weil es unterhaltsam ist, auch wenn man damit fachlich nichts anfangen kann. Vielleicht sind wir ja so unterhaltsam, ich weiß es nicht. Oder wir reden irgendwie alle Chinesisch.
Aber wenn es halt nicht gut ist, lasst uns das auch wissen. Das ist auch wertvoller Input. Und dann machen wir demnächst mal wieder was irgendwie mit so, hier, wie heißt das Zeug? CSS und so. Oh Gott, jetzt habe ich die Shownotes unserer vorherigen Revision React-Halsbringer oder Höllenmaschine aufgemacht.
Und mit den Shownotes ist nichts verkehrt, aber dann bin ich jetzt wieder auf dieser trumpcard.gov-Seite mit dem Adler-PNG-Video. Und wisst ihr, jetzt glaube ich wirklich, dass ich irgendwie was mit Steinen machen sollte, statt mit Software. Alles bisher irgendwie, ah, any und funktioniert eh nicht und spricht nicht zusammen und man kann nicht mal irgendwie dem Weltbild von Typescript selber in sich glauben.
Alles ist Blödsinn. Aber wenn ich wieder diesen PNG-Adler sehe, da geht mir jetzt wirklich wieder der Glauben an die Menschheit und an die Existenz auf dieser Realitäts-Ebene flöten. Ja, ne? Ey! Ich hatte das erfolgreich verdrängt. Ich bin mir nicht sicher, wie dieser Tag bei mir jetzt noch eine Kurve kriegen soll. Ich meine, man kann es ja so sehen.
Was ist Kunst? Kunst ist doch dann, wenn man bei seinem Publikum eine emotionale Reaktion erzeugt. Ich glaube, wir müssen diese Webseite unter Kunst rubrizieren. Gut, ich habe gehört, manche von uns haben bis vor drei Minuten Zeit, Ja, also bei mir wird es Zeit, dass ihr weiter noch bei mir Aber ich danke euch recht herzlich, Gleichfalls Es war ein Vergnügen wie sonst was Wie immer, liebe Hörerinnen, liebe Hörer Wir haben es schon gesagt, lasst euer Feedback erklingen auf Social Media oder haut uns auch sonst an, wenn ihr uns irgendwo seht.
Ich habe keine Ahnung, was die nächste Revision ist Deswegen höre ich jetzt auf zu quatschen. Danke fürs Zuhören. Bis zum nächsten Mal und tschüss. Ciao.