Saltar al contenido principal
Móvil Capacitor

Ejemplo de API en TypeScript para Capacitor y Capgo

Explora un ejemplo práctico de TypeScript API para plugins de Capacitor y actualizaciones de Capgo. Domina interfaces tipadas, patrones de listener y estrategias de implementación.

Ejemplo de API en TypeScript para Capacitor y Capgo

Todo sólido ejemplo de TypeScript API para Capacitor empieza igual: con una interfaz de plugin tipada. Define explícitamente tus métodos, opciones y resultados de Promise, y tu code web y la capa nativa compartirán un contrato que TypeScript realmente aplica.

Tabla de contenidos

Crea una interfaz de plugin Capacitor fuertemente tipada

La interfaz describe el API que tu code web ve. La implementación nativa detrás debe cumplir ese contrato, y TypeScript verifica nombres de métodos, parámetros y valores de retorno antes de que tu app se ejecute.

import { registerPlugin } from ‘@capacitor/core’;

export interface DeviceStatus { online: boolean; batteryLevel?: number; }

export interface DevicePlugin { getStatus(): Promise;\nsetLabel(options: { label: string }): Promise<{ saved: boolean }>;\n}

export const Device = registerPlugin(‘Device’);

Hay mucho que hacer en esas pocas líneas:

  • Tipos de retorno explícitos mantienen cada resultado predecible.
  • Objetos de opciones tipados detecta propiedades faltantes o mal escritas en tiempo de compilación.
  • Métodos basados en Promise modelan el trabajo nativo que termina de forma asíncrona.
  • Un genérico registerPlugin llamar es lo que conecta el API web con el bridge nativo.
  • Interfaces documentan el contrato sin añadir ni un byte de code en runtime.

Cada punto de llamada recibe el mismo tratamiento:

const status = await Device.getStatus(); console.log(status.online);

await Device.setLabel({ label: ‘Production’ });

Cambiar { label: 'Production' } para { name: 'Production' } y el compilador lo marca en el momento. Eso es mejor que descubrir la discrepancia después de una publicación móvil.

La interface también es donde modelas valores opcionales y casos de fallo. Si un método nativo no siempre puede producir una lectura de batería, batteryLevel?: number indica a cada llamador que gestione undefined.

El diagrama siguiente muestra cómo los métodos tipados, las opciones, los valores de retorno, las definiciones del bridge y las comprobaciones en tiempo de compilación se conectan dentro de Capacitor API.

Un diagrama que ilustra los principales beneficios de una interfaz de plugin de TypeScript fuertemente tipada para frameworks de desarrollo móvil.

La idea central: las definiciones de tipo fluyen desde la interfaz web hacia la lógica de la plataforma nativa, y las comprobaciones en tiempo de compilación vigilan cada punto de llamada.

Consulta rápida para el diseño de API

Elemento Propósito Ejemplo
Firma del método Define el comportamiento invocable getStatus()
Tipo Options Controla la forma de la entrada { label: string }
Resultado Promise Representa trabajo asíncrono Promise<DeviceStatus>
Interfaz Result Define los datos devueltos online: boolean

Para una referencia más profunda, lee la guía sobre construir APIs en TypeScript. Dos hábitos que conviene mantener: no incluyas secretos ni credenciales de firma en el cliente code, y prueba la interfaz contra cada implementación de plataforma antes de publicar.

Los equipos móviles manejan JavaScript, code nativo, permisos de dispositivo y servicios de plataforma asíncronos al mismo tiempo. Un contrato sólido de TypeScript funciona como una lista de verificación compartida en cada uno de esos límites, haciendo explícitas las expectativas antes de que cualquier code llegue a un dispositivo iOS o Android.

Una persona programando en un portátil que muestra code sobre un escritorio, junto a una taza de café.

Para un ejemplo concreto ejemplo de TypeScript API, compara un método que devuelve Promise<DeviceStatus> con uno que devuelve datos sin tipar. La versión tipada le dice a tu editor y a cada revisor exactamente qué campos existen. La versión sin tipar traslada ese trabajo de descubrimiento a los logs de runtime, pruebas manuales y, en el peor caso, incidentes en producción.

Señales de adopción

TypeScript ha superado con creces su nicho de front-end. La adopción subió a 35% de los desarrolladores en 2024, frente a solo 12% en 2017, and more than un millón de contribuidores de GitHub lo eligieron como su lenguaje principal para 2025. Profundiza en el hallazgos sobre la adopción de TypeScript si quieres los datos crudos.

Esa trayectoria importa para las organizaciones móviles de formas prácticas. La contratación, el onboarding y la revisión de code giran cada vez más en torno a tipos compartidos. Alguien que se une a un proyecto de Capacitor puede leer una interfaz y entender el comportamiento nativo esperado sin rastrear cada implementación.

Las APIs tipadas también facilitan razonar sobre el trabajo de release. Cuando un método exige un objeto de opciones específico, una propiedad renombrada o un campo faltante falla en tiempo de compilación en lugar de generar silenciosamente una solicitud nativa incompleta.

El tipado fuerte desplaza el feedback crítico a la izquierda, cuando una corrección toma minutos en lugar de un release de hotfix de emergencia.

Beneficios para equipos de Capacitor

Las apps multiplataforma suelen exponer una única API orientada a web que se apoya sobre varias implementaciones nativas. TypeScript no puede probar que cada detalle nativo se comporte de forma idéntica, pero puede mantener tus llamadas consistentes en toda la aplicación.

Aplica tipos explícitos a:

  • Entradas de métodos, incluyendo opciones requeridas y opcionales
  • Resultados de Promise, para que los datos de éxito tengan siempre una forma predecible
  • Eventos y listeners, para que los callbacks manejen payloads conocidos
  • Errores y valores de estado, para que las rutas de fallback sean visibles

Esa estructura rinde frutos al integrar plugins de dispositivos o servicios operativos. También ayuda a los equipos que revisan la automatización de actualizaciones, donde un canal, bundle identifier o campo de compatibilidad erróneo puede afectar a una gran base de usuarios.

Para profundizar en patrones relacionados, lee nuestra guía para generar APIs tipadas con OpenAPI. Aborda cómo las definiciones compartidas reducen la deriva manual que suele aparecer entre la documentación de API y el code de la aplicación.

Hacer el caso de negocio

La tipificación estricta requiere cierta inversión inicial, especialmente cuando el code JavaScript antiguo tiene formas de datos inconsistentes. El retorno se nota con el tiempo: refactorizaciones más pequeñas, propiedad más clara y muchas menos sorpresas de integración.

Empieza por los límites que conllevan más riesgo:

  1. Define interfaces de respuesta para llamadas nativas y remotas.
  2. Tipa tus objetos de opciones y payloads de eventos.
  3. Turn on strict compiler checks incrementally.
  4. Exige comprobaciones de tipos antes de publicar cualquier actualización.

Para equipos móviles empresariales, esa base hace predecible el mantenimiento entre plataformas, releases y colaboradores.

El ScreenOrientationPlugin de Capacitor es un gran ejemplo de TypeScript API porque mapea un puñado de métodos web simples al comportamiento del dispositivo específico de cada plataforma. El contrato público permanece idéntico entre plataformas, mientras que iOS y Android gestionan sus propios detalles nativos por debajo.

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;\nlock(options: LockOptions): Promise;\nunlock(): Promise;\naddListener(\neventName: ‘screenOrientationChange’,\nlistenerFunc: (data: OrientationData) => void,\n): Promise<{ remove: () => Promise }>; }

export const ScreenOrientation = registerPlugin(‘ScreenOrientation’);

Aquí tienes la referencia rápida de cada firma:

  • orientation() — lee la orientación actual de forma asíncrona
  • lock() — solo acepta un valor de orientación conocido
  • unlock() — devuelve el control al comportamiento normal del dispositivo
  • addListener() — dispara un payload tipado cada vez que cambia la orientación

Como cada método devuelve una Promise, puedes usar el mismo patrón de llamada contra el bridge nativo y contra una implementación de navegador. Sin ramificaciones, sin casos especiales.

const current = await ScreenOrientation.orientation();

if (current.type.startsWith(‘landscape’)) { console.log(Angle: ${current.angle}); }

await ScreenOrientation.lock({ orientation: ‘landscape-primary’, });

Escribe un valor con error ortográfico como landscape-main y el build falla al instante. Es un error de compilación que corriges en segundos, no un bug de runtime específico de la plataforma que persigues a través de los logs del dispositivo.

Tipa correctamente los argumentos del listener

Los Listeners merecen el mismo rigor que los métodos regulares. Evita any aquí, porque oculta la diferencia entre un payload de evento y el resultado orientation() que devuelve.

const handleChange = (data: OrientationData) => { document.body.dataset.orientation = data.type; };

const subscription = await ScreenOrientation.addListener( ‘screenOrientationChange’, handleChange, );

await subscription.remove();

Solo comparte un único OrientationData type cuando ambas implementaciones nativas garantizan los mismos campos. Si una plataforma omite angle, márcalo como opcional y obliga a los llamadores a manejar undefined.

Decisión de diseño Patrón más seguro
Entradas Interfaces de opciones con nombre
Resultados Tipos de Promise explícitos
Eventos Nombres de eventos literales
Limpiar Devuelve una suscripción eliminable

La interfaz es el contrato del bridge, no la implementación nativa. Manténlo pequeño, predecible y testeable.

Para el comportamiento de la plataforma, permisos y pasos de instalación, lee la guía del plugin Capacitor Screen Orientation. Un último hábito que vale la pena adoptar: prueba tanto llamadas válidas como rechazadas con configuraciones estrictas de TypeScript. Esa combinación detecta nombres de métodos incorrectos, campos faltantes y payloads de listeners incompatibles mucho antes de empaquetar tu aplicación móvil.

Capgo ofrece a los equipos de Capacitor una forma de empujar correcciones de JavaScript, CSS, configuración y assets sin pasar por la revisión de la app store. El truco es tratar su pipeline de actualizaciones como cualquier otra frontera tipada de API, para que los canales, reglas de rollout, comprobaciones de compatibilidad y decisiones de rollback sean explícitos antes de que un bundle llegue al dispositivo de un usuario.

Una persona sosteniendo un smartphone que muestra la diferencia entre la orientación de pantalla vertical y horizontal.

Define los contratos de actualización

Empieza definiendo exactamente qué valores acepta tu automatización. Las uniones literales evitan que despliegues por error al canal equivocado, y las interfaces hacen que la relación entre un bundle y su versión nativa requerida sea autodocumentada.

type Channel = ‘beta’ | ‘staging’ | ‘production’;

interface UpdateRequest {\nchannel: Channel;\nbundleVersion: string;\nminNativeVersion: string;\nrolloutPercent: number;\nsigned: boolean;\n}

interface UpdateResult {\naccepted: boolean;\nappliedOnNextLaunch: boolean;\nrollbackEnabled: boolean;\n}

Un enfoque directo ejemplo de TypeScript API valida la solicitud antes de pasarla al cliente Capgo:

async function publishUpdate(\nrequest: UpdateRequest,\n): Promise {\nif (!request.signed || request.rolloutPercent < 0 ||\nrequest.rolloutPercent > 100) {\nthrow new Error(‘Unsafe update request’);\n}\n}

return capgo.publish(request);\n}

El nombre exacto del método del cliente cambia entre versiones de Capgo SDK, así que envuélvelo detrás de tu propia interfaz. Ese aislamiento se paga cada vez que haces una actualización y evita que los detalles específicos del proveedor se filtren en tu base de código.

Proteger canales y compatibilidad

Elegir un canal no debería ser casual. Un lanzamiento a producción exige comprobaciones más estrictas que un experimento beta, especialmente cuando el bundle web llama a capacidades nativas que no existían en versiones anteriores de la app.

function canDeploy( request: UpdateRequest, installedNativeVersion: string, ): boolean { return request.signed && installedNativeVersion >= request.minNativeVersion; }

No compares versiones con cadenas simples. Usa una librería de semantic-versioning adecuada para que 1.10.0 ordena después 1.9.0. Antes de que nada llegue a un canal, pasa por una lista de verificación:

  1. Confirma que el bundle está firmado.
  2. Verifica que el canal destino coincida con la intención.
  3. Compara los rangos de compatibilidad entre native y bundle.
  4. Publica primero para una audiencia limitada.
  5. Monitorea las señales de fallo y mantén el rollback listo.

Un pipeline de updates tipado convierte la política de release en code que los revisores y la CI pueden inspeccionar realmente.

La entrega diferencial y el control de canales de Capgo encajan bien en ese patrón, y su observabilidad a nivel de dispositivo permite a los equipos rastrear señales de adopción o fallo a posteriori. Para la parte de instrumentación de eventos, consulta esta guía de seguimiento de eventos personalizados con Capgo.

Las claves de firma y las credenciales de administrador deben estar en el servidor o en el sistema de CI, no en la app distribuida. Aplica la actualización en el próximo arranque, prueba el rollback con un bundle rechazado a propósito y registra cada decisión con un resultado tipado. Esa combinación mantiene la entrega rápida compatible con un control disciplinado de las versiones móviles.

Los listeners tipados son los que hacen que las APIs asíncronas sean fáciles de confiar. Ya sea que un callback siga la orientación de pantalla o un evento de actualización de Capgo, debe recibir la misma estructura de payload en todas las plataformas — y el compilador debería ser quien lo garantice.

interface UpdateEvent { version: string; channel: ‘beta’ | ‘production’; available: boolean; }

type Listener = (payload: T) => void;

interface UpdateService { addListener( event: ‘updateAvailable’, callback: Listener, ): Promise<{ remove: () => Promise }>;\nremoveAllListeners(): Promise; }

Esto ejemplo de TypeScript API fija el nombre del evento a un literal y vincula el callback a un payload tipado. Tu editor autocompleta version gratis, y el compilador rechaza cualquier callback que espere datos no relacionados. Es poco setup, y compensa cada vez que cambia API.

¿Prefieres verlo en acción? Mira la demostración:

Registra listeners de forma segura

Dentro de un componente, conserva el handle de la suscripción para que la limpieza sea explícita. El mismo patrón funciona en los hooks de ciclo de vida de Angular, los efectos de React y los hooks de montaje de Vue sin cambios.

let orientationHandle: { remove: () => Promise } | undefined;

async function start() { orientationHandle = await ScreenOrientation.addListener( ‘screenOrientationChange’, ({ type, angle }) => { console.log(type, angle); }, ); }

async function stop() { await orientationHandle?.remove(); orientationHandle = undefined; }

Ejecuta la limpieza cuando una pantalla desaparece, no solo cuando se cierra toda la app. Si lo omites, la navegación deja callbacks adjuntos a fuentes de eventos nativas. Terminarás con trabajo duplicado y actualizaciones de estado obsoletas que son difíciles de rastrear.

Cada framework te ofrece un hook para esto:

  • Angular — ejecuta la limpieza desde ngOnDestroy
  • React — devuelve una función de limpieza segura para async desde useEffect
  • Vue — elimina la suscripción en onBeforeUnmount

Cada addListener llamada debe tener una ruta de eliminación correspondiente.

Elige el método de limpieza adecuado

Un handle devuelto es la opción correcta cuando un componente posee una suscripción. removeAllListeners() brilla cuando un servicio mantiene varios listeners y se está reiniciando por completo.

async function resetUpdates(service: UpdateService) { await service.removeAllListeners(); }

No ejecutes el método amplio desde un componente compartido mientras otras pantallas sigan dependiendo del servicio. Si la propiedad es local, quédate con los remove() handles.

Situación Acción recomendada
Suscripción de un componente Llama a handle.remove()
Apagado del servicio Llama a removeAllListeners()
Registro repetido Inicialización de guard
Payload desconocido Validar antes de usar

Para las notificaciones de Capgo, mantén los payloads de actualización separados de los eventos del dispositivo. Luego prueba el registro, la entrega y la limpieza por separado: el Capgo custom event tracking guide tiene más detalles sobre la integración.

Antes de publicar, verifica tres cosas: que el desmontaje elimine realmente los manejadores, que las promesas rechazadas se capturen y que ningún callback pueda actualizar un componente destruido. Esa disciplina mantiene las apps reactivas de Capacitor responsivas en Angular, React y Vue.

Un desarrollador de software profesional trabajando en code en una configuración de doble monitor mientras usa auriculares.

Un buen diseño ejemplo de TypeScript API comienza con nombres que describen la intención. Usa verbos para métodos, sustantivos para interfaces y mantén sufijos consistentes como Options, Result, y Event. Nombres claros reducen el tiempo de onboarding, ya que los desarrolladores entienden el contrato sin abrir la implementación.

Mantén las interfaces públicas pequeñas. Expón capacidades mediante métodos enfocados en lugar de volcar operaciones poco relacionadas en un solo objeto.

  • getStatus() lee el estado.
  • updateConfig(options) cambia la configuración.
  • addListener(event, callback) se suscribe a los cambios.

Tipa Inputs y Outputs con precisión

Usa interfaces de opciones nombradas cuando los parámetros puedan crecer:

interface PublishOptions { channel: ‘beta’ | ‘production’; rolloutPercent: number; }

interface PublishResult { version: string; accepted: boolean; }

async function publish( options: PublishOptions, ): Promise { return client.publish(options); }

Los genéricos justifican su uso cuando un API envuelve distintos payloads pero necesita preservar sus tipos específicos:

interface ApiResponse { data: T; requestId: string; }

async function request(path: string): Promise<ApiResponse> { return fetchJson<ApiResponse>(path); }

Pero no añadas genéricos solo para parecer flexible. Un genérico debe expresar una relación real entre la entrada y la salida; de lo contrario, una interfaz concreta es más fácil de leer y mantener.

Haz que los estados inválidos sean difíciles de representar, especialmente en los límites de native, red y actualizaciones.

Documenta el comportamiento junto al contrato. Cubre permisos, unidades, promesas rechazadas, campos opcionales y si un método se aplica de inmediato o en el próximo lanzamiento. Los comentarios en línea deben explicar decisiones, no repetir nombres de métodos.

Organiza Code para el cambio

Separa tipos, lógica del cliente, adaptadores de plataforma y pruebas en archivos predecibles. Exporta los tipos públicos desde un único punto de entrada y mantén los detalles de implementación privados.

Aspecto Ubicación recomendada
Interfases públicas types.ts
Métodos de API client.ts
Adaptadores nativos platform/
Pruebas de compatibilidad tests/

Para cambios de plugins que rompen compatibilidad, introduce una nueva interfaz mayor o capa de compatibilidad, mantén los métodos obsoletos temporalmente y documenta los pasos de migración. Más sobre estrategias de versionado de API antes de modificar a los consumidores.

Ejecuta comprobaciones de tipos estrictas y pruebas de contrato en CI antes de publicar. Para flujos de trabajo de Capgo, verifica valores de canal, compatibilidad nativa, bundles firmados y comportamiento de rollback como reglas de lanzamiento tipadas: esto mantiene las actualizaciones rápidas bajo control a medida que crecen los equipos, plataformas e integraciones.

¿Cómo debo tipar resultados nativos dinámicos?

No dejes que any se filtre en tu code cuando un método nativo devuelva datos impredecibles. En su lugar, especifica los campos en los que puedes confiar y marca los valores realmente opcionales con ?, y sanea la entrada incierta en el límite antes de que nada aguas abajo la toque.

interface NativeResult { success: boolean; value?: string; }

async function readValue(): Promise { const result = await NativePlugin.read(); return { success: Boolean(result.success), value: typeof result.value === ‘string’ ? result.value : undefined, }; }

Este enfoque mantiene seguros a tus llamadores mientras hace explícita la incertidumbre en el propio tipo. Para una visión más amplia de este patrón de interfaz, repasa construir APIs en TypeScript.

¿Cómo pueden los listeners evitar rechazos no gestionados?

Las callbacks asíncronas deben ser defensivas por diseño. Captura los fallos dentro del propio listener en lugar de confiar en que el sistema de eventos trague las promesas rechazadas en silencio.

const handleUpdate = (event: UpdateEvent): void => { void applyUpdate(event).catch((error: unknown) => { console.error('Update failed', error); }); };

Mantén la referencia de la suscripción y elimínala cuando el componente se desmonte. Esto evita callbacks duplicados y actualizaciones de estado obsoletas; la sección sobre el ciclo de vida del listener lo detalla.

Cada listener asíncrono necesita tanto una ruta de error como una de limpieza.

¿Cómo protejo las actualizaciones de Capgo?

Las claves de firma y las credenciales administrativas se quedan en tu servidor o sistema de CI. Punto. El cliente solo debe recibir bundles firmados y usar resultados tipados para mostrar el estado, nunca para crear firmas.

Antes de publicar, configura uniones de canales separadas, ejecuta comprobaciones de compatibilidad, establece límites de rollout y planifica tu ruta de rollback. Capgo gestiona la entrega firmada, el control de canales, la aplicación en el próximo lanzamiento y la protección de rollback para apps de Capacitor y Electron. Su documentación muestra cómo los flujos de release tipados pueden endurecer tu pipeline de actualizaciones.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.