使用 mapToClass 时,Dexie 不会在查询时返回类类型

问题描述 投票:0回答:1

我正在尝试在项目中使用 Dexie,并且尝试同时使用 Typescript 和

.mapToClass
功能。当尝试实现 Dexie: Typescript 中的示例时,我得到了一些混合结果。这是我的意思的一个例子:

设置

模型/Entry.ts

export default abstract class Entry<T extends {}> {
  constructor(props: T, hiddenPropKeys?: string[]) {
    // merge props with instance to initialize all props from the interface/class
    Object.assign(this, props);

    // programmatically adding non-serializable keys
    hiddenPropKeys?.forEach((key) =>
      Object.defineProperty(this, key, { writable: true }),
    );
  }
}

模型/Friend.ts

import db from '../db';
import Entry from './Entry';

interface IFriend {
  id?: number;
  name: string;
  relationship: string;
}

const table = db.friends;
type Type = IFriend; // shorthand, mainly for the static method

// doing this instead of having to iterate over every interface member again, as part of the class 
interface Friend extends Type {
  addresses: string[]
}
// eslint-disable-next-line no-redeclare
class Friend extends Entry<Type> {
  constructor(params: Type) {
    super(params, ['addresses']);
  }

  save() {
    /* do some stuff to process the Friend */
    return table.put(this);
  }

  getAddresses() {
    /* some method to grab addresses and store them locally */
    this.addresses = ['123 Main St', '55 Foo Bar Ln'];
  }

  // static helper basically do a db lookup
  // I was thinking to add a caching layer here as well
  // it won't stop you from attempting to search by non-indexed fields, but neither will Dexie
  static find<T extends keyof Type>(
    key: T,
    value: Required<Type>[T] | Required<Type>[T][],
  ) {
    const query = table.where(key);
    return value instanceof Array ? query.anyOf(value) : query.equals(value);
  }
}

// the Dexie sugar
table.mapToClass(Friend);

export default Friend;

db.ts

import Dexie, { Table } from 'dexie';
import { IFriend } from './models/Friend';

export class DataBase extends Dexie {
  friends!: Table<IFriend, number>;

  constructor() {
    super('Projector');
    this.version(1).stores({
      friends: '++id, &name'
    });
  }
}

const db = new DataBase();

问题

Main.ts

...
const friend = await Friend.find('name', 'Frank').toArray();
console.log(friend instanceof Friend); 
// true <<< good

friend.getAddresses(); 
// TS: Property 'getAddresses' does not exist on type 'IFriend' <<< the issue
...

由于某种原因,

toArray()
的结果如通过
mapToClass()
所宣传的那样返回,但未正确键入以与 TypeScript 一起使用。有什么办法可以解决这个问题吗?

我尝试过的事情

我尝试编写一个自定义插件,但我认为这没有任何用处。

db.Table.prototype.toArray = Dexie.override(
  db.Table.prototype.toArray,
  function (original) {
    return function () {
      return original
        .apply(this, arguments)

        // this would be dynamic, ideally, but i was just trying to get something to happen
        .map((entry) => entry as Friend); 
    };
  },
);

我也可以手动做这样的事情:

const friends = await Friend.find('name', ['Fred', 'Bob']).toArray(f => f as Friend[]);

但这有点违背了目的。

我也尝试过将

Table
类型切换为使用
Friend
来代替

...
export class DataBase extends Dexie {
  friends!: Table<Friend, number>; // Class instead of interface

  constructor() {
    super('Projector');
    this.version(1).stores({
      friends: '++id, &name'
    });
  }
}
...

但是在添加新行时只会引发错误,因为由于某种原因,这些方法似乎被枚举到类型中。

预先感谢您的帮助

typescript indexeddb dexie
1个回答
0
投票

此问题已在 dexie 4 中得到解决。请参阅 https://dexie.org/roadmap/dexie4.0#distinguish-insert--from-output-types

使用

npm install dexie@next
安装 dexie@4。

© www.soinside.com 2019 - 2024. All rights reserved.