Codegen für TurboModules: typsichere Schnittstellen generieren
AI generated
RN
native
React Native / New Architecture
Codegen für TurboModules
Typsichere native Schnittstellen aus einer einzigen Spec generieren

Codegen verwandelt eine TypeScript-Spec-Datei in die einzige Quelle der Wahrheit für ein TurboModule und erzeugt daraus zur Buildzeit passenden Interface-Code für iOS und Android. Dieser Artikel zeigt, was Codegen dabei tatsächlich tut, wie eine neue TurboModule-Spec in der Praxis entsteht und welche Fehlerklasse gegenüber manuell geschriebenen Bridging-Deklarationen komplett verschwindet.

10 Min. Lesezeit Codegen TurboModules Typsicherheit

1. Warum manuelles Bridging fehleranfällig war

In der alten Architektur wurde jedes NativeModule manuell mit passenden Methodensignaturen auf iOS und Android nachgebaut, wobei JavaScript zur Laufzeit lediglich per Reflection oder String-basiertem Lookup herausfand, welche Methoden überhaupt existierten. Eine falsch geschriebene Methode, ein vergessener Parameter oder ein Typmismatch zwischen JavaScript und nativer Implementierung fiel oft erst als Laufzeitfehler auf, manchmal erst bei einem seltenen Codepfad in Produktion.

Da beide Plattformen unabhängig voneinander gepflegt wurden, driftete die iOS- und die Android-Implementierung eines Moduls im Laufe der Zeit häufig auseinander, etwa wenn ein neuer Parameter nur auf einer Plattform ergänzt wurde. Codegen setzt genau hier an: eine einzige, typisierte Spec-Datei wird zur einzigen Quelle der Wahrheit, aus der beide Plattformen konsistent generiert werden.

Zusätzlich erschwerte die alte, lose gekoppelte Bridging-Deklaration jede größere Refaktorierung, weil ein Team beim Umbenennen einer Methode auf beiden Plattformen gleichzeitig manuell nachziehen musste, ohne dass der Compiler an irgendeiner Stelle auf die verbliebene Inkonsistenz hinwies. Gerade in größeren Teams mit getrennten iOS- und Android-Entwicklern führte das regelmäßig zu Reibungsverlusten, die mit einer einzigen, verbindlichen Spec-Datei strukturell verschwinden.

2. Wie Codegen arbeitet: von der TypeScript-Spec zum generierten Code

Codegen liest zur Buildzeit spezielle TypeScript-Dateien, die per Namenskonvention als NativeXyz.ts erkannt werden und ein Interface exportieren, das TurboModule erweitert. Aus diesem Interface erzeugt ein Parser zunächst eine plattformunabhängige Schema-Repräsentation als JSON, die alle Methoden, Parametertypen und Rückgabewerte in einer maschinenlesbaren Form beschreibt.

Aus diesem Schema generieren separate Codegen-Backends dann die tatsächlichen Artefakte je Plattform: für iOS Objective-C++ Protokolle und Header, für Android Java-Interfaces und die passenden JNI-Bindings. Der generierte Code landet in einem Build-Verzeichnis und wird bei jedem Build neu erzeugt, weshalb er niemals von Hand editiert werden sollte.

3. Eine TurboModule-Spec anlegen: NativeMyModule.ts

Eine Spec-Datei folgt einer strengen, eingeschränkten Teilmenge von TypeScript, damit Codegen sie zuverlässig parsen kann. Erlaubt sind bestimmte primitive Typen, Arrays, Objekte mit fest definierter Form sowie einige spezielle Typen wie Double oder UnsafeObject für Fälle, in denen keine feste Struktur vorliegt. Generische TypeScript-Features wie Union-Types mit mehr als zwei Optionen oder komplexe Mapped Types werden bewusst nicht unterstützt.

Das folgende Beispiel zeigt eine minimale, gültige Spec-Datei mit einer synchronen und einer asynchronen Methode, exakt so, wie Codegen sie als Vertrag zwischen JavaScript und nativer Seite interpretiert.


import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  getDeviceId(): string;
  getBatteryLevel(): Promise<number>;
  multiply(a: number, b: number): number;
}

export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');

4. Der generierte Code im Detail: Schema, Header und Interfaces

Für das Beispielmodul erzeugt Codegen unter anderem eine JSON-Schema-Datei mit der abstrakten Methodenbeschreibung, ein Objective-C++ Protokoll NativeMyModuleSpec mit exakt passenden Methodensignaturen für iOS sowie ein Java-Interface NativeMyModuleSpec für Android, das die native Klasse implementieren muss. Beide generierten Interfaces spiegeln die TypeScript-Spec bis auf Typkonvertierung exakt wider.

Wichtig ist, dass diese generierten Dateien reine Verträge sind, keine Implementierung. Die eigentliche native Klasse muss das generierte Interface implementieren, und der Compiler meldet einen Fehler, sobald eine Methode fehlt oder eine falsche Signatur hat, was in der alten, manuell gepflegten Bridging-Welt schlicht nicht existierte.

5. Implementierung auf iOS: Objective-C++ gegen das generierte Protokoll

Die iOS-Implementierung erbt von NSObject, konformiert zum generierten Protokoll NativeMyModuleSpec und implementiert jede Methode mit exakt passender Signatur. Für asynchrone Methoden wie getBatteryLevel übernimmt der generierte Code bereits die Umwandlung in ein JavaScript Promise, die native Implementierung muss nur noch resolve oder reject aufrufen.

Registriert wird das Modul über die generierte Factory-Methode getTurboModule, die der TurboModuleManager beim ersten Zugriff aus JavaScript aufruft. Anders als bei alten NativeModules entfällt hier das manuelle Makro RCT_EXPORT_METHOD für jede einzelne Methode, da die gesamte Methodenliste bereits aus der Spec bekannt ist.

6. Implementierung auf Android: Kotlin gegen das generierte Java-Interface

Auf Android implementiert die Kotlin-Klasse das generierte Interface NativeMyModuleSpec, das von der abstrakten Basisklasse ReactContextBaseJavaModule abgeleitet ist. Jede Methode muss exakt der generierten Signatur entsprechen, inklusive der für Promises nötigen Promise-Parameter bei asynchronen Methoden.

Die Registrierung erfolgt über ein TurboReactPackage, das in seiner getModule-Methode eine Instanz der Klasse zurückgibt sowie über getReactModuleInfoProvider Metadaten für die Turbo-Module-Erkennung liefert. Fehlt einer dieser beiden Bestandteile, findet der TurboModuleManager das Modul zur Laufzeit nicht, meldet aber einen klaren Fehler statt eines stillen Fehlschlags.

7. Registrierung, Podspec und Autolinking

Damit Codegen ein Modul überhaupt findet, muss die Podspec auf iOS beziehungsweise die build.gradle auf Android auf die Codegen-Konfiguration verweisen, üblicherweise über einen Eintrag in der package.json unter codegenConfig, der Name und Pfad der Spec-Dateien deklariert. React Native Autolinking scannt diese Konfiguration automatisch bei jedem Build und bindet neue Module ein, ohne dass native Projektdateien von Hand angepasst werden müssen.

Für lokale Module innerhalb eines Monorepos, die nicht als separates npm-Paket veröffentlicht werden, reicht ein passender codegenConfig-Eintrag im App-eigenen package.json, solange die Spec-Datei über den konfigurierten jsSrcsDir auffindbar ist.

8. Typsicherheit: welche Fehler Codegen zur Buildzeit abfängt

Codegen fängt vor allem strukturelle Fehler ab: fehlende Methoden, falsche Parameteranzahl, inkompatible Typen zwischen der Spec und der nativen Implementierung sowie vergessene Promise-Parameter bei asynchronen Methoden. Diese Fehlerklasse führte in der alten Architektur regelmäßig zu Crashes, die erst beim tatsächlichen Aufruf der betroffenen Methode auftraten, oft weit entfernt vom eigentlichen Implementierungsort.

Nicht abgefangen werden dagegen semantische Fehler, etwa eine Methode, die laut Spec eine gültige Geräte-ID zurückgibt, tatsächlich aber einen leeren String liefert. Codegen prüft ausschließlich die Struktur des Vertrags, nicht dessen inhaltliche Korrektheit, weshalb Unit-Tests für die eigentliche Business-Logik weiterhin notwendig bleiben.

9. Workflow-Tipps: Monorepos, lokale Libraries und Debugging von Codegen-Fehlern

In einem Monorepo mit mehreren Paketen lohnt es sich, Spec-Dateien konsequent in einem eigenen specs-Verzeichnis pro Paket zu bündeln und den codegenConfig-Eintrag darauf zu verweisen, statt Spec-Dateien verstreut neben beliebigem anderen Code abzulegen. Das erleichtert es, bei einem fehlgeschlagenen Codegen-Lauf schnell die betroffene Datei zu finden.

Codegen-Fehler äußern sich meist als kryptische Parserfehler mit Zeilennummer in der generierten Zwischendarstellung, nicht direkt in der Spec-Datei. In der Praxis hilft es, verdächtige TypeScript-Konstrukte wie komplexe Union-Types oder optionale, verschachtelte Objekte schrittweise zu vereinfachen, bis der Codegen-Lauf wieder durchläuft, und danach die Komplexität kontrolliert zurückzubauen.

Aspekt Manuelles Bridging (alt) Codegen für TurboModules Konkreter Nutzen
Quelle der Wahrheit Getrennte iOS- und Android-Implementierung Eine TypeScript-Spec-Datei Keine Drift zwischen Plattformen
Fehlererkennung Laufzeitfehler bei Typmismatch Compile-Zeit-Fehler bei falscher Signatur Fehler fallen vor dem Release auf
Async-Handling Manuelles Promise/Callback-Mapping Automatisch generierter Promise-Wrapper Weniger Boilerplate pro Methode
Registrierung RCT_EXPORT_METHOD je Methode Interface-Implementierung, kein Makro Weniger manuelle Pflege bei neuen Methoden
Monorepo-Eignung Schwer synchron zu halten codegenConfig pro Paket deklarierbar Konsistente Module über mehrere Pakete

Mironsoft

React-Native-App-Entwicklung und Magento-Anbindung

Eine mobile App zum Magento-Shop, die wirklich rund läuft?

Wir entwickeln React-Native-Apps, die sauber an die Magento REST- oder GraphQL-API angebunden sind, von der ersten Codezeile bis zur Veröffentlichung im App Store und bei Google Play.

App-Konzeption

Architektur und Feature-Umfang einer Magento-angebundenen App gemeinsam planen.

Magento-API-Integration

Produktkatalog, Warenkorb und Checkout sauber an die Shop-API anbinden.

Store-Veröffentlichung

App Store- und Google-Play-Freigabeprozess ohne Stolperfallen begleiten.

10. Zusammenfassung

Codegen für TurboModules: Das Wichtigste auf einen Blick

Spec-Datei

Eine TypeScript-Datei mit eingeschränkter Syntax ist die einzige Quelle der Wahrheit für ein TurboModule.

Codegen-Backends

Erzeugen aus dem Schema separate, plattformspezifische Interfaces für iOS und Android.

Buildzeit-Sicherheit

Strukturelle Fehler wie falsche Signaturen fallen beim Kompilieren auf, nicht erst zur Laufzeit.

Grenzen

Codegen prüft nur die Struktur des Vertrags, semantische Korrektheit bleibt Aufgabe eigener Tests.

11. FAQ: Codegen für TurboModules: Das Wichtigste auf einen Blick

1Was ist der Unterschied zwischen einer TurboModule-Spec und der eigentlichen Implementierung?
Die Spec ist eine TypeScript-Datei, die den Vertrag definiert, aus dem Codegen native Interfaces generiert. Die Implementierung ist der native Code, der diese generierten Interfaces auf iOS und Android tatsächlich umsetzt.
2Welche TypeScript-Features unterstützt Codegen?
Nur eine eingeschränkte Teilmenge: primitive Typen, Arrays, fest definierte Objektformen und einige Spezialtypen. Komplexe generische Konstrukte wie mehrgliedrige Union-Types werden nicht unterstützt.
3Muss ich den generierten Code manuell anpassen?
Nein, generierter Code entsteht bei jedem Build neu und sollte niemals von Hand editiert werden, Änderungen gehören ausschließlich in die Spec-Datei.
4Wie meldet Codegen fehlende Methoden?
Nicht direkt, sondern indirekt: Fehlt eine Methode in der nativen Implementierung, meldet der native Compiler einen klassischen Fehler wegen eines nicht vollständig implementierten Interfaces oder Protokolls.
5Funktioniert Codegen auch für lokale Module in einem Monorepo?
Ja, über einen passenden codegenConfig-Eintrag in der package.json, der den Pfad zu den Spec-Dateien deklariert, auch ohne separate npm-Veröffentlichung.
6Was passiert bei einem Typmismatch zwischen Spec und Implementierung?
Der native Compiler bricht den Build ab, da die Implementierung das generierte Interface oder Protokoll nicht mehr korrekt erfüllt, statt eines stillen Laufzeitfehlers.
7Kann ich asynchrone Methoden in der Spec definieren?
Ja, über einen Promise-Rückgabetyp in TypeScript, aus dem Codegen automatisch die passende resolve/reject-Struktur für iOS und Android generiert.
8Prüft Codegen auch die inhaltliche Korrektheit meiner Methoden?
Nein, Codegen prüft ausschließlich die strukturelle Übereinstimmung zwischen Spec und Implementierung, nicht die tatsächliche Logik dahinter. Dafür bleiben eigene Tests notwendig.
9Warum bekomme ich einen kryptischen Parserfehler beim Codegen-Lauf?
Meist wegen eines nicht unterstützten TypeScript-Konstrukts in der Spec-Datei. Es hilft, verdächtige Stellen schrittweise zu vereinfachen, bis der Lauf wieder erfolgreich durchläuft.
10Ersetzt Codegen das Autolinking?
Nein, beide Mechanismen ergänzen sich: Autolinking bindet Module und ihre Codegen-Konfiguration automatisch in native Projekte ein, Codegen generiert die eigentlichen typisierten Interfaces daraus.