TypeScript Interface Merging and Extending Modules

FilePond is split up in a core library and a wide range of plugins. The plugins add properties to the core. But how do we extend the core TypeScript Interface to show the plugin properties?

Let’s take a look.

We have a core library, in this case FilePond, and we have a plugin that dynamically adds a property called allowFilePoster to the core instance.

import { create } from "filepond";

import FilePondPluginFilePoster from "filepond-plugin-file-poster";

const instance = create(inputElement, {
  allowFilePoster: true, // error!
});

If the 'filepond-plugin-file-poster' module doesn’t extend the core interface, TypeScript will throw this error:

/* Property 'allowFilePoster' does not exist on type 'FilePond'. ts(2339) */

And rightly so, because this property isn’t available on the core interface.

To quickly work around this we could define the property in the core interface, but that would make third-party plugin development impossible as they wouldn’t have access to the core interface.

Instead we need a way to extend the core interface with additional declarations.

Searching “extend interface” doesn’t yield a lot of answers as extending interfaces is also possible with TypeScript but it’s not what we want, we want to add declarations to an existing interface.

Adding declarations to an interface

The FilePond module exports the FilePondOptions interface, it’s located in the types/index.d.ts folder of the repository.

export interface FilePondOptions {
  /** Enable or disable drag n’ drop */
  allowBrowse?: boolean;

  // Other FilePond core options here...
}

In the plugin repository types we set things up like shown below.

We import 'filepond' and then, declare a module under the same name, and then extend the core FilePondOptions interface.

// @ts-ignore
import { FilePondOptions } from "filepond";

declare module "filepond" {
  export interface FilePondOptions {
    /** Enable or disable file poster */
    allowFilePoster?: boolean;

    // Other FilePond plugin options here...
  }
}

Note that in my development environment I had to add the @ts-ignore statement to prevent it from throwing the following warning.

/* 'FilePondOptions' is declared but its value is never read. ts(6133) */

Now if both the core and the plugin modules have been imported, the allowFilePoster property is recognized on the FilePond instance and we can set it without it throwing an error.

You can read more on this in the official TypeScript documentation in this entry about extending modules.

Rik Schennink

Web enthusiast

to pqina.nl