Chaque solide exemple concret de API TypeScript pour Capacitor commence de la même façon : par une interface de plugin typée. Définissez explicitement vos méthodes, options et résultats Promise, et votre code web ainsi que la couche native partageront un contrat que TypeScript applique réellement.
Table des matières
- Créez une interface de plugin Capacitor fortement typée
- Référence rapide pour le design de API
- Signaux d'adoption
- Avantages pour les équipes Capacitor
- Démontrer la valeur métier
- Typer correctement les arguments du listener
- Définir des contrats de mise à jour
- Sécuriser les canaux et la compatibilité
- Enregistrer les listeners en toute sécurité
- Choisir la bonne méthode de nettoyage
- Typer précisément les entrées et sorties
- Organiser Code pour évoluer
- Comment typer les résultats natifs dynamiques ?
- Comment éviter les rejets non gérés dans les listeners ?
- Comment protéger les mises à jour Capgo ?
Créez une interface de plugin Capacitor fortement typée
L'interface décrit l’API que voit votre code web. L'implémentation native derrière doit respecter ce contrat — et TypeScript vérifie les noms de méthodes, les paramètres et les valeurs de retour avant même l'exécution de votre app.
import { registerPlugin } from ‘@capacitor/core’;
export interface DeviceStatus {\nonline: boolean;\nbatteryLevel?: number;\n}
export interface DevicePlugin {\ngetStatus(): Promise}
export const Device = registerPlugin
Il se passe beaucoup de choses dans ces quelques lignes :
- Types de retour explicites rendent chaque résultat prévisible.
- Objets d'options typés détecter les propriétés manquantes ou mal orthographiées à la compilation.
- Méthodes basées sur les promesses modèle natif dont le travail s’achève de manière asynchrone.
- Un générique
registerPluginAppelez est ce qui connecte le web API au pont natif. - Interfaces documenter le contrat sans ajouter un seul octet de runtime code.
Chaque site d’appel reçoit le même traitement :
const status = await Device.getStatus(); console.log(status.online);
await Device.setLabel({ label: ‘Production’ });
Remplacez { label: 'Production' } pour { name: 'Production' } et le compilateur le signale immédiatement. C’est bien mieux que de découvrir l’incohérence après une release mobile.
C’est aussi dans l’interface que vous modélisez les valeurs optionnelles et les cas d’échec. Si une méthode native ne peut pas toujours produire une mesure de batterie, batteryLevel?: number indique à chaque appelant de gérer undefined.
Le schéma ci-dessous montre comment les méthodes typées, les options, les valeurs de retour, les définitions de bridge et les vérifications à la compilation s’articulent au sein d’un Capacitor API.

L’idée centrale : les définitions de types circulent de l’interface web vers la logique des plateformes natives, et les contrôles à la compilation protègent chaque site d'appel.
Référence rapide pour le design de API
| Élément | Objectif | Exemple |
|---|---|---|
| Signature de la méthode | Définit le comportement appelable | getStatus() |
| Type d'options | Contrôle la forme des entrées | { label: string } |
| Résultat de la Promise | Représente une tâche asynchrone | Promise<DeviceStatus> |
| Interface Result | Définit les données renvoyées | online: boolean |
Pour aller plus loin, lisez le guide sur la création d'API en TypeScript. Deux bonnes pratiques à retenir : garder les secrets et les identifiants de signature hors du code côté client, et tester l'interface avec chaque implémentation de plateforme avant de publier.
Les équipes mobiles jonglent en même temps avec JavaScript, le code natif, les permissions d'appareil et les services de plateforme asynchrones. Un contrat TypeScript solide agit comme une checklist partagée à chacune de ces frontières, en rendant les attentes explicites avant qu'un code n'arrive sur un appareil iOS ou Android.

Pour un exemple concret exemple concret de API TypeScript, comparez une méthode qui retourne Promise<DeviceStatus> avec une autre qui renvoie des données non typées. La version typée indique à votre éditeur et à chaque relecteur exactement quels champs existent. La version non typée fait peser ce travail de découverte sur les logs d'exécution, les tests manuels et, au pire, les incidents en production.
Signaux d'adoption
TypeScript a largement dépassé sa niche front-end. Son adoption a atteint 35 % des développeurs en 2024, contre seulement 12 % en 2017, et plus d' un million de contributeurs GitHub l'ont désigné comme leur langage principal d'ici 2025. Plongez dans les résultats de l' adoption de TypeScript si vous voulez les chiffres bruts.
Cette trajectoire a un impact concret pour les organisations mobiles. Le recrutement, l'onboarding et la revue de code s'articulent de plus en plus autour de types partagés. Quelqu'un qui rejoint un projet Capacitor peut lire une interface et comprendre le comportement natif attendu sans avoir à parcourir chaque implémentation.
Les API typées facilitent aussi la compréhension du travail de release. Lorsqu'une méthode exige un objet d'options spécifique, une propriété renommée ou un champ manquant échoue à la compilation au lieu de produire silencieusement une requête native incomplète.
Le typage fort permet de détecter les erreurs plus tôt, quand un correctif prend quelques minutes au lieu d'une release d'urgence.
Avantages pour les équipes Capacitor
Les applications cross-platform exposent généralement un API web unique qui repose sur plusieurs implémentations natives. TypeScript ne peut pas prouver que chaque détail natif se comporte de manière identique, mais il peut garantir la cohérence de vos appels dans toute l'application.
Appliquez des types explicites à :
- Entrées de méthode, y compris les options requises et facultatives
- Résultats de Promise, pour que les données de succès aient toujours une structure prévisible
- Événements et listeners, pour que les callbacks gèrent des payloads connus
- Erreurs et valeurs de statut, ainsi les chemins de repli restent visibles
Cette structure se révèle payante quand on intègre des plugins d'appareil ou des services opérationnels. Elle aide aussi les équipes qui passent en revue l'automatisation des mises à jour, où un canal, un identifiant de bundle ou un champ de compatibilité erroné peut toucher une large base d'utilisateurs.
Pour approfondir les patterns associés, lisez notre guide sur la génération d'API typées avec OpenAPI. Il explique comment les définitions partagées réduisent le décalage manuel qui s'installe habituellement entre la documentation API et le code de l'application.
Démontrer la valeur métier
Le typage strict demande un certain investissement initial, surtout quand d'anciens code JavaScript portent des structures de données incohérentes. Le retour se fait sentir avec le temps : des refactors plus petits, une répartition des responsabilités plus claire et bien moins de surprises d'intégration.
Commencez par les frontières les plus à risque :
- Définissez des interfaces de réponse pour les appels natifs et distants.
- Typez vos objets d'options et vos payloads d'événements.
- Activez progressivement les vérifications strictes du compilateur.
- Exigez des vérifications de types avant de publier une mise à jour.
Pour les équipes mobiles d’entreprise, cette base rend la maintenance prévisible entre les plateformes, les releases et les contributeurs.
Le ScreenOrientationPlugin de Capacitor est un excellent exemple concret de API TypeScript car il mappe quelques méthodes web simples sur le comportement natif de l’appareil. Le contrat public reste identique sur toutes les plateformes, tandis qu’iOS et Android gèrent chacun leurs détails natifs en interne.
import { registerPlugin } from ‘@capacitor/core’;
export type OrientationType = | ‘portrait-primary’ | ‘portrait-secondary’ | ‘landscape-primary’ | ‘landscape-secondary’;
export interface OrientationData { type: OrientationType; angle: number; }
export interface LockOptions { orientation: OrientationType; }
export interface ScreenOrientationPlugin {
orientation(): Promise
export const ScreenOrientation =
registerPlugin
Voici la référence rapide pour chaque signature :
orientation()— lit l’orientation actuelle de manière asynchronelock()— n’accepte qu’une valeur d’orientation connueunlock()— rend la main au comportement normal de l’appareiladdListener()— déclenche un payload typé à chaque changement d’orientation
Comme chaque méthode renvoie une Promise, vous pouvez utiliser le même schéma d’appel côté pont natif et côté implémentation navigateur. Aucun branchement, aucun cas particulier.
const current = await ScreenOrientation.orientation();
if (current.type.startsWith(‘landscape’)) {
console.log(Angle: ${current.angle});
}
await ScreenOrientation.lock({ orientation: ‘landscape-primary’, });
Saisissez une valeur mal orthographiée comme landscape-main et le build échoue immédiatement. C’est une erreur de compilation que vous corrigez en quelques secondes — pas un bug d’exécution spécifique à la plateforme que vous traquez dans les logs de l’appareil.
Typer correctement les arguments du listener
Les listeners méritent la même rigueur que les méthodes classiques. Évitez any ici, car cela masque la différence entre le payload d’un événement et le résultat orientation() retourne.
const handleChange = (data: OrientationData) => { document.body.dataset.orientation = data.type; };
const subscription = await ScreenOrientation.addListener( ‘screenOrientationChange’, handleChange, );
await subscription.remove();
N’exposez qu’un seul OrientationData type lorsque les deux implémentations natives garantissent les mêmes champs. Si une plateforme omet angle, marquez-le comme optionnel et forcez les appelants à le gérer undefined.
| Choix de conception | Pattern plus sûr |
|---|---|
| Entrées | Interfaces d'options nommées |
| Résultats | Types de Promise explicites |
| Événements | Noms d'événements littéraux |
| Nettoyage | Retourner un abonnement supprimable |
L'interface est le contrat du bridge, pas l'implémentation native. Gardez-le petit, prévisible et testable.
Pour le comportement par plateforme, les autorisations et les étapes d’installation, consultez guide du plugin Capacitor Screen Orientation. Une dernière habitude à adopter : tester à la fois les appels valides et les appels rejetés avec des paramètres TypeScript stricts. Cette combinaison détecte les noms de méthodes erronés, les champs manquants et les payloads de listeners incompatibles bien avant de packager votre application mobile.
Capgo permet aux équipes Capacitor de pousser des correctifs JavaScript, CSS, de configuration et d’assets sans attendre la revue des stores. L’astuce consiste à traiter son pipeline de live updates comme n’importe quelle frontière typée API, afin que les canaux, les règles de déploiement progressif, les vérifications de compatibilité et les décisions de rollback restent explicites avant qu’un bundle n’atteigne l’appareil d’un utilisateur.

Définir des contrats de mise à jour
Commencez par définir précisément les valeurs que votre automatisation accepte. Les unions littérales vous évitent de déployer par erreur vers le mauvais canal, et les interfaces documentent d’elles-mêmes la relation entre un bundle et la version native requise.
type Channel = ‘beta’ | ‘staging’ | ‘production’;
interface UpdateRequest { channel: Channel; bundleVersion: string; minNativeVersion: string; rolloutPercent: number; signed: boolean; }
interface UpdateResult { accepted: boolean; appliedOnNextLaunch: boolean; rollbackEnabled: boolean; }
Une approche simple exemple concret de API TypeScript valide la requête avant de la transmettre au client Capgo :
async function publishUpdate(
request: UpdateRequest,
): Promise
return capgo.publish(request); }
Le nom exact de la méthode client change selon les versions de Capgo SDK, donc encapsulez-la derrière votre propre interface. Cette isolation est rentable à chaque mise à jour et empêche les détails propres au fournisseur de fuiter dans votre codebase.
Sécuriser les canaux et la compatibilité
Le choix d'un canal ne doit pas se faire à la légère. Une release en production exige des vérifications plus strictes qu'une expérimentation bêta, surtout lorsqu'un bundle web appelle des capacités natives qui n'existaient pas dans les versions antérieures de l'app.
function canDeploy( request: UpdateRequest, installedNativeVersion: string, ): boolean { return request.signed && installedNativeVersion >= request.minNativeVersion; }
Ne comparez pas les versions avec de simples chaînes. Utilisez une bibliothèque de versionnage sémantique pour 1.10.0 se trie après 1.9.0. Avant d'envoyer quoi que ce soit sur un canal, passez par cette checklist :
- Confirmez que le bundle est signé.
- Vérifiez que le canal cible correspond à l'intention.
- Comparez les plages de compatibilité natif/bundle.
- Publiez d'abord auprès d'une audience limitée.
- Surveillez les signaux d'échec et gardez un rollback prêt.
Un pipeline de mise à jour typé transforme la politique de release en code que les reviewers et la CI peuvent réellement inspecter.
La livraison différentielle et les contrôles de canaux de Capgo s'intègrent parfaitement à ce modèle, et son observabilité au niveau de l'appareil permet aux équipes de retracer l'adoption ou les signaux d'échec après coup. Pour l'instrumentation des événements, consultez ce guide sur le suivi des événements personnalisés avec Capgo.
Les clés de signature et les identifiants admin doivent rester sur le serveur ou le système de CI, pas dans l'app livrée. Appliquez la mise à jour au prochain lancement, testez le rollback avec un bundle rejeté intentionnellement, et loguez chaque décision avec un résultat typé. Cette combinaison concilie une livraison rapide avec un contrôle rigoureux des releases mobiles.
Les listeners typés, c'est ce qui permet de faire confiance aux API asynchrones. Qu'il s'agisse d'un callback qui suit l'orientation de l'écran ou d'un événement de mise à jour Capgo, il doit recevoir la même structure de payload sur chaque plateforme — et c'est au compilateur de le garantir.
interface UpdateEvent {\nversion: string;\nchannel: ‘beta’ | ‘production’;\navailable: boolean;\n}
type Listener
interface UpdateService {\naddListener(\nevent: ‘updateAvailable’,\ncallback: Listener
Ceci exemple concret de API TypeScript fixe le nom de l'événement sur un littéral et lie le callback à un payload typé. Votre éditeur autocomplète version gratuitement, et le compilateur rejette tout callback qui attend des données sans rapport. C'est un peu de configuration, mais ça vaut le coup à chaque fois que l’API change.
Vous préférez le voir en action ? Regardez la démo :
Enregistrer les listeners en toute sécurité
À l'intérieur d'un composant, conservez le handle de la souscription pour que le nettoyage reste explicite. Ce même pattern se transpose aux hooks de cycle de vie Angular, aux effets React et aux hooks de montage Vue sans modification.
let orientationHandle: { remove: () => Promise }
async function start() { orientationHandle = await ScreenOrientation.addListener( 'screenOrientationChange', ({ type, angle }) => { console.log(type, angle); }, ); }
async function stop() {\nawait orientationHandle?.remove();\norientationHandle = undefined;\n}
Exécutez le nettoyage lorsqu'un écran disparaît — pas seulement quand l'application entière se ferme. Si vous l'oubliez, la navigation laisse des callbacks attachés aux sources d'événements natifs. Vous vous retrouvez avec du travail en double et des mises à jour d'état obsolètes, pénibles à tracer.
Chaque framework propose un hook pour cela :
- Angular — déclencher le nettoyage depuis
ngOnDestroy - React — renvoyer une fonction de nettoyage sûre en asynchrone depuis
useEffect - Vue — supprimer l’abonnement dans
onBeforeUnmount
Chaque
addListenerUn appel doit avoir un chemin de suppression correspondant.
Choisir la bonne méthode de nettoyage
Retourner un handle est le bon choix lorsqu’un composant possède un seul abonnement. removeAllListeners() brille lorsqu’un service détient plusieurs listeners et doit être entièrement réinitialisé.
async function resetUpdates(service: UpdateService) { await service.removeAllListeners(); }
Ne déclenchez pas la méthode générale depuis un composant partagé alors que d’autres écrans dépendent encore du service. Si la propriété est locale, restez sur des remove() handles.
| Situation | Action recommandée |
|---|---|
| Abonnement d’un composant | Appelez handle.remove() |
| Arrêt du service | Appelez removeAllListeners() |
| Enregistrement répété | Initialisation du guard |
| Payload inconnu | Valider avant utilisation |
Pour les notifications Capgo, séparez les payloads de mise à jour des événements de l'appareil. Testez ensuite l'enregistrement, la livraison et le nettoyage séparément — le Guide de suivi des événements personnalisés Capgo contient plus de détails sur l'intégration.
Avant de déployer, vérifiez trois points : le démontage supprime bien les handlers, les promesses rejetées sont bien interceptées, et aucun callback ne peut mettre à jour un composant détruit. Cette discipline garantit la réactivité des apps Capacitor sur Angular, React et Vue.

Un code bien conçu exemple concret de API TypeScript commence par des noms qui décrivent l'intention. Utilisez des verbes pour les méthodes, des noms pour les interfaces, et gardez des suffixes cohérents comme Options, Result, et EventDes noms clairs réduisent le temps d'onboarding car les développeurs saisissent le contrat sans avoir à ouvrir l'implémentation.
Gardez les interfaces publiques légères. Exposez les capacités via des méthodes ciblées plutôt que de regrouper des opérations peu liées sur un seul objet.
getStatus()lit l'état.updateConfig(options)modifie la configuration.addListener(event, callback)s'abonne aux changements.
Typer précisément les entrées et sorties
Préférez les interfaces d'options nommées lorsque les paramètres peuvent évoluer :
interface PublishOptions { channel: ‘beta’ | ‘production’; rolloutPercent: number; }
interface PublishResult { version: string; accepted: boolean; }
async function publish(
options: PublishOptions,
): Promise
Les generics se justifient quand un API enveloppe différents payloads mais doit préserver leurs types spécifiques :
interface ApiResponse
async function request
Mais n'ajoutez pas de génériques juste pour paraître flexible. Un générique doit exprimer une relation réelle entre l'entrée et la sortie — sinon, une interface concrète est plus facile à lire et à maintenir.
Rendez les états invalides difficiles à représenter, en particulier aux limites du natif, du réseau et des Live Update.
Documentez le comportement juste à côté du contrat. Couvrez les permissions, les unités, les promesses rejetées, les champs optionnels, et précisez si une méthode s'applique immédiatement ou au prochain lancement. Les commentaires inline doivent expliquer les décisions, pas répéter le nom de la méthode.
Organiser Code pour évoluer
Séparez les types, la logique client, les adaptateurs de plateforme et les tests dans des fichiers prévisibles. Exportez les types publics depuis un point d'entrée unique et gardez les détails d'implémentation privés.
| Enjeu | Emplacement recommandé |
|---|---|
| Interfaces publiques | types.ts |
| Méthodes API | client.ts |
| Adaptateurs natifs | platform/ |
| Tests de compatibilité | tests/ |
Pour les changements de plugin majeurs, introduisez une nouvelle interface majeure ou une couche de compatibilité, conservez temporairement les méthodes obsolètes et rédigez les étapes de migration. En savoir plus sur les stratégies de versioning API avant de modifier les consommateurs.
Exécutez des vérifications de types strictes et des tests de contrat en CI avant de déployer. Pour les workflows Capgo, vérifiez les valeurs de canal, la compatibilité native, la signature des bundles et le comportement de rollback via des règles de release typées — cela permet de garder les mises à jour rapides sous contrôl’à mesure que les équipes, les plateformes et les intégrations grandissent.
Comment typer les résultats natifs dynamiques ?
Ne laissez pas any fuiter dans votre code lorsqu'une méthode native renvoie des données imprévisibles. À la place, définissez explicitement les champs sur lesquels vous pouvez compter, marquez les valeurs réellement optionnelles avec ?, et assainissez les entrées incertaines à la limite du système avant qu'elles ne soient traitées par la suite.
interface NativeResult {\nsuccess: boolean;\nvalue?: string;\n}
async function readValue(): Promise
Cette approche protège vos appelants tout en rendant l’incertitude explicite dans le type lui-même. Pour une vue d’ensemble plus large de ce motif d’interface, consultez à nouveau la création d'API en TypeScript.
Comment éviter les rejets non gérés dans les listeners ?
Les callbacks asynchrones doivent être pensés de manière défensive. Capturez les échecs directement dans le listener plutôt que de compter sur le système d’événements pour avaler silencieusement les promesses rejetées.
const handleUpdate = (event: UpdateEvent): void => { void applyUpdate(event).catch((error: unknown) => { console.error('Update failed', error); }); };
Conservez la référence de l’abonnement et supprimez-la lorsque le composant se démonte. Cela évite les callbacks en double et les mises à jour d’état obsolètes — la section sur le cycle de vie des listeners détaille ce point.
Chaque listener asynchrone nécessite à la fois un chemin d’erreur et un chemin de nettoyage.
Comment protéger les mises à jour Capgo ?
Les clés de signature et les identifiants administratifs restent sur votre serveur ou votre système CI. Point final. Le client ne doit jamais recevoir que des bundles signés et utiliser des résultats typés pour afficher l’état — jamais pour créer des signatures.
Avant de publier, configurez des unions de canaux distinctes, exécutez les vérifications de compatibilité, définissez les limites de déploiement progressif et planifiez votre rollback. Capgo gère la livraison signée, le contrôle des canaux, l'application au prochain lancement et la protection contre le rollback pour Capacitor et les apps Electron. Leur documentation montre comment des workflows de release typés peuvent resserrer votre pipeline de mise à jour.