Calling addListener in TypeScript to add event listener to Capacitor Plugin

I am writing a Capacitor plugin for an Ionic Vue application. My question is pretty simple. I am getting an error when running “ionic build” in my Ionic app when it is trying to register the callback to subscribe to plugin events: “TS2339: Property ‘addListener’ does not exist on type ‘MyPlugin’.”

I have the following bit of code in my Ionic Vue project:

import { MyPlugin } from "@valmarc/myplugin"
.....
MyPlugin.addListener("myPluginEvent", myCallback)

The TypeScript compiler error occurs on the “addListener” call above. The above code was written against following capacitor documentation: Capacitor - build cross platform apps with the web.

The error is not particularly surprising, because the datatype of “MyPlugin” is defined as follows in the auto-generated TypeScript file “index.ts”:

import { registerPlugin } from '@capacitor/core';
import type { MyPluginPlugin } from './definitions';
const MyPlugin= registerPlugin<MyPluginPlugin>('MyPlugin', {
    web: () => import('./web').then(m => new m.MyPluginWeb()),
});
export * from './definitions';
export { MyPlugin };

The above auto-generated code seems to assign an object of type “MyPluginPlugin” to the MyPlugin variable, which is exported. The type “MyPluginPlugin” is defined as follows in the “definitions.ts” file:

export interface MyPlugin {
      createState(options: { source: string}): Promise<{ id: number}>;
      callFunction(options: { id: number, function: string}): Promise<{ result: string}>;
      closeState(options: { id: number}): Promise<void>;
}

My plugin interface above does not define the “addListener” method that is referred to in the Capacitor documentation I referred to above.

So obviously I am missing something here. Where is the “addListener” method supposed to be declared on the object that is returned from registerPlugin? Unless the addListener method is declared somewhere, there is going to be a TypeScript error.

1 Like

In case anyone sees this in the future, the problem is that there is a bug in the auto-generated code to define a capacitor plugin.

If you create a plugin with the standard tool using “npx @capacitor/create-plugin”, then you will find that it auto-generates a file called “definitions.ts”, which contains the following 3 lines of code:

export interface ExamplePlugin {
    echo(options: { value: string }): Promise<{ value: string }>;
}

The above code is wrong, and should instead be the following:

import { Plugin } from '@capacitor/core'
export interface ExamplePlugin extends Plugin {
  echo(options: { value: string }): Promise<{ value: string }>;
}

This allows your plugin to have the “addListener” method declared on it, so you don’t get a TypeScript compiler error when you try to call it, as shown in the documentation here: “Capacitor - build cross platform apps with the web”.

Probably a bug should be filed so this can be fixed, and other people don’t waste hours of time like I did.

3 Likes

Thanks! I’m glad I stumbled upon this sooner rather than later. I was also having troubles getting the addListener to be recognized and didn’t realize I needed to extend the Plugin on my typing interface as well.

It’s not a bug, the recommended way is adding addListener definitions in the definitions.ts file for every listener available, so the users can know the event name and what the callback returns instead of using the generic addListener that users just know that the event name is a string and the callback is a function and can make mistakes when typing the event name.

example capacitor-plugins/keyboard/src/definitions.ts at be3dd6889b5d147cd43ff17ae2cfdb936a146a34 · ionic-team/capacitor-plugins · GitHub