0

It seem I cant find solution on this. using upsert on pouchdb I am getting TS2345 and or TS2339.

I tried using it like htis.

db.upsert('id', doc => {
  doc.p = 'sample';
  return doc;
});

but on the doc.p I am getting TS2339 Property 'p' does not exist on type '{} | IdMeta'

and base on pouchdb-upsert/index.d.ts it has this definition

upsert<Model>(docId: Core.DocumentId, diffFun: UpsertDiffCallback<Content & Model>): Promise<UpsertResponse>;

So I tried this

db.upsert<{ p: string }>('id', doc => {
  doc.p = 'sample';
  return doc;
});

but now I am getting TS2345 and TS2339. here is the error

Argument of type '(doc: {} | Document<{ p: string; }>) => {} | Document<{ p: string; }>' is not assignable to parameter of type 'UpsertDiffCallback<{ p: string; }>'.
   Type '{} | Document<{ p: string; }>' is not assignable to type 'false | "" | 0 | ({ p: string; } & Partial<IdMeta>) | null | undefined'.
     Type '{}' is not assignable to type 'false | "" | 0 | ({ p: string; } & Partial<IdMeta>) | null | undefined'.
       Type '{}' is not assignable to type '{ p: string; } & Partial<IdMeta>'.
         Type '{}' is not assignable to type '{ p: string; }'.
           Property 'p' is missing in type '{}'. (typescript-tide)

Anyone? please, thanks.

Update

When I test it like this:

  public test() {
    new PouchDB('test').upsert<{ p: string }>('id', doc => {
      doc.p = 'test string';
      return doc;
    })
  }

I am getting this:

Argument of type '(doc: Partial<Document<{ p: string; }>>) => Partial<Document<{ p: string; }>>' is not assignable to parameter of type 'UpsertDiffCallback<{ p: string; }>'.
   Type 'Partial<Document<{ p: string;; }>>' is not assignable to type 'false | "" | 0 | ({ p: string; } & Partial<IdMeta>) | null | undefined'.
     Type 'Partial<Document<{ p: string; }>>' is not assignable to type '{ p: string; } & Partial<IdMeta>'.
       Type 'Partial<Document<{ p: string; }>>' is not assignable to type '{ p: string; }'.
         Types of property 'p' are incompatible.
           Type 'string | undefined' is not assignable to type 'string'.
             Type 'undefined' is not assignable to type 'string'. (typescript-tide)

While if I do it like this:

  public test2() {
    new PouchDB<{ p: string }>('test').upsert('id', doc => {
      doc.p = 'test string';
      return doc;
    })
  }

I am getting this:

Argument of type '(doc: Partial<Document<{ p: string; }>>) => Partial<Document<{ p: string; }>>' is not assignable to parameter of type 'UpsertDiffCallback<{ p: string; } & Partial<Document<{ p: string; }>>>'.
   Type 'Partial<Document<{ p: string; }>>' is not assignable to type 'false | "" | 0 | ({ p: string; } & Partial<Document<{ p: string; }>> & Partial<IdMeta>) | null | ...'.
     Type 'Partial<Document<{ p: string; }>>' is not assignable to type '{ p: string; } & Partial<Document<{ p: string; }>> & Partial<IdMeta>'.
       Type 'Partial<Document<{ p: string; }>>' is not assignable to type '{ p: string; }'.
         Types of property 'p' are incompatible.
           Type 'string | undefined' is not assignable to type 'string'.
             Type 'undefined' is not assignable to type 'string'. (typescript-tide)
Community
  • 1
  • 1
zer09
  • 1,507
  • 2
  • 28
  • 48

1 Answers1

1

The root of the problem is that your diffFun receives the argument {} if the document does not exist, and that type does not have any fields. I've submitted a pull request to DefinitelyTyped to change the argument type to Partial<Core.Document<Content & Model>>, which will be more useful since it will allow you to assign to fields. (See this answer for the possible ways to use my modified declarations until the pull request is merged.)

However, if you use a document type with required fields such as { p: string }, you still won't be able to return doc without a type assertion because TypeScript still thinks that doc has only an optional property. You could specify the document type as { p?: string } and then your code will compile without error. But if you do expect all documents in the database to have a p property, it's probably better practice to use { p: string } and have each diffFun either use a type assertion or return a new object, so you're reminded that you need to initialize all required properties in the case that the document didn't exist.

Matt McCutchen
  • 28,856
  • 2
  • 68
  • 75
  • Thanks! BTW your PR is still not merged, I just patch my index.d.ts but I still got this ```(doc: Partial>) => void' is not assignable to parameter of type 'UpsertDiffCallback<{ p: string; } & void>``` . And if I wont specify the document type, I am getting this ```(doc: Partial) => void' is not assignable to parameter of type 'UpsertDiffCallback``` – zer09 Nov 13 '18 at 23:55
  • Did you remove the `return doc` statement from the `diffFun`? The function is required to return the new document. If that wasn't it, please update the question with your latest code so I can reproduce the problem. – Matt McCutchen Nov 14 '18 at 03:00
  • sorry, I didn't add the ```return doc``` but when I did, please see the update above. – zer09 Nov 14 '18 at 03:44
  • Ah. This is the issue I mentioned in the second paragraph of the answer. You'll need to use a type assertion before returning `doc`, for example, `return <{p: string}>doc;`. – Matt McCutchen Nov 14 '18 at 03:59