jakearchibald / idb

IndexedDB, but with promises
https://www.npmjs.com/package/idb
ISC License
6.22k stars 348 forks source link

Support request: Wrapping stores in custom classes #230

Open rudolfbyker opened 2 years ago

rudolfbyker commented 2 years ago

Thanks for this great package.

I'm trying to use a custom class to manage a certain type of store, of which there could be many instances. This works in Javascript, but I'm getting stuck when implementing this in Typescript.

Here is a self-contained demo:

import { DBSchema, IDBPDatabase, StoreNames } from "idb";

export interface OurSchema extends DBSchema {
  foo: {
    key: number;
    value: {
      a: number;
      b: number;
      c: number;
    };
    indexes: {
      d: number;
      e: number;
    };
  };
  bar: {
    key: number;
    value: {
      f: number;
      g: number;
      h: number;
    };
    indexes: {
      i: number;
      j: number;
    };
  };
}

class SpecialStore<
  DBTypes extends DBSchema,
  StoreName extends StoreNames<DBTypes>
> {
  /**
   * This indexedDb database backing this store.
   */
  public readonly db: IDBPDatabase<DBTypes>;

  /**
   * The name of the store.
   */
  public readonly name: StoreName;

  /**
   * The path to the key inside each item object.
   */
  public readonly keyPath: string | string[];

  constructor(
    db: IDBPDatabase<DBTypes>,
    name: StoreName,
    keyPath: string | string[]
  ) {
    this.db = db;
    this.name = name;
    this.keyPath = keyPath;
  }

  // ... other special methods
}

function createStore(
  db: IDBPDatabase<OurSchema>
): SpecialStore<OurSchema, "foo"> {
  return new SpecialStore<OurSchema, "foo">(db, "foo", "a");
}

This is the type error I'm getting:

64:28 Type 'string' does not satisfy the constraint 'never'.
    62 | function createStore(
    63 |   db: IDBPDatabase<OurSchema>
  > 64 | ): SpecialStore<OurSchema, "foo"> {
       |                            ^
    65 |   return new SpecialStore<OurSchema, "foo">(db, "foo", "a");
    66 | }

image

(Strangely enough, this error does not occur in codepen.io with the same code: https://codepen.io/dolf/pen/WNjZWWK . I'm assuming codepen just doesn't show TS errors.)

I would expect StoreNames<DBTypes> to resolve to "foo" | "bar" in this case, but somehow it results in never. Why would that be?

rudolfbyker commented 2 years ago

Note that I do get proper type hinting that name must be "foo" when the generic requires it:

image