Declare extensions to a Typescript library

Viewed 46

I'm using Sequency's extendSequence() utility to add a custom method to all Sequence instances:

import Sequence, { extendSequence, isSequence } from 'sequency'
import equal from '@wry/equality'

class SequencyExtensions {
  equals<T>(this: Sequence<T>, other: Sequence<T> | Iterable<T>): boolean {
    const as = this.iterator
    const bs = isSequence(other) ? other.iterator : other[Symbol.iterator]()
    while (true) {
      const a = as.next()
      const b = bs.next()
      if (a.done && b.done) return true
      if (a.done !== b.done || !equal(a.value, b.value)) return false
    }
  }
}

extendSequence(SequencyExtensions)

It works in development mode (Next.js development mode), but both my IDE (WebStorm) and the build process fail with an error, saying that the custom method does not exist:

asSequence([1,2,3]).equals([1,2,3])
                    ^^^^^^
                    TS2339: Property 'equals' does not exist on type 'Sequence '.

I tried merging a definition with the original interface and importing it alongside the previous snippet of code, that actually implements it, but I'm missing something because both the IDE and the bulid tool ignore it:

declare module 'sequency' {
  interface Sequence<T> {
    /**
     * Returns `true` if this sequence is equal to the other sequence or iterable.
     *
     * @param {Sequence | Iterable} other
     * @returns {boolean}
     */
    equals<T>(this: Sequence<T>, other: Sequence<T> | Iterable<T>): boolean
  }
}

What is the correct way to merge a custom method into an imported interface?

1 Answers

I found the problem.

Since the Sequence interface is defined like this:

export default interface Sequence<T> ...

I also had to include the exact same export qualifiers in my extension:

declare module 'sequency' {
  export default interface Sequence<T> {
  // ^^^^^^^^^^^
    ...
  }
}
Related