Search code examples
typescriptpouchdbtypescript-typingsdefinitelytyped

How to work around incorrect (?) TypeScript/DefinitelyTyped typings for PouchDB?


I'm looking for help with TypeScript and the PouchDB type declarations. Consider this TS code:

import PouchDB = require('pouchdb')
import find = require('pouchdb-find')
PouchDB.plugin(find)

const data = new PouchDB("http://localhost:5984/data"),

export async function deleteLastRevForIds(dbname, ids) {
  const docsToDelete = await data.find({
    fields: ["_id", "_rev"],
    selector: { _id: { $in: ids } }
  })

  const deletePromise = docsToDelete.docs.map(doc => {
    return data.remove(doc) // <-- HERE TSC SHOUTS AT ME about `doc`
  })
  const deletion = await Promise.all(deletePromise)
  return deletion
}

At the annotated remove() call, tsc emits this error:

Argument of type 'IdMeta' is not assignable to parameter of type 'RemoveDocument'.
  Type 'IdMeta' is not assignable to type 'RevisionIdMeta'.
    Property '_rev' is missing in type 'IdMeta'.'

What's happening is that the find() call is typed by the DefinitelyTyped typings as returning a {docs: PouchDB.Core.IdMeta[]}. And as its name implies, a PouchDB.Core.IdMeta[] means an array of {_id: string}.

But it's false! PouchDB.find() doesn't return just a list of {_id: ...} objects, it returns a list of {_id: ..., _rev: ...} (plus I asked for these two fields explicitly). Or am I missing something?

As a result, when calling the remove() function (correctly typed by the DT typings as needing an fully-specified _id+_rev RevisionIdMeta) with such an object, TS rightly shouts at me.

I tried casting this thing in all directions but couldn't bend it to my will; tsc keeps erroring that _rev is missing from my object.

  • Is there a way for me do such a "deep" cast?
  • If not, is there a way to override the DT typings as locally as possible?
  • Should I be doing something else entirely?

Also, should I propose a change to the DT typings?

Thanks.


Solution

  • Yeah, the Pouchdb-find definitions are wrong. Something like this should get you moving...

    const data = new PouchDB("http://localhost:5984/data")
    
    interface FixedFindResponse<Content extends PouchDB.Core.Encodable> {
      docs: PouchDB.Core.ExistingDocument<Content>[];
    }
    export async function deleteLastRevForIds(dbname: void, ids: number[]) {
      const docsToDelete: FixedFindResponse<any> = await data.find({
        fields: ["_id", "_rev"],
        selector: { _id: { $in: ids } }
      })
    
      const deletePromise = docsToDelete.docs.map(doc => {
        return data.remove(doc) // <-- HERE TSC SHOUTS AT ME about `doc`
      })
      const deletion = await Promise.all(deletePromise)
      return deletion
    }