如何使这个 class 可以在打字稿中重复使用?元编程?子class是吗?注入模块?

how do I make this class reuseable in typescript? meta programming? subclasses? injected module?

我有这个 EventsStorage typescript class,它负责在离子存储(sqlite 和 indexedDB 的包装器)中存储和检索事件对象。它始终使用我的事件 class。

我想为事件以外的其他东西重用很多这种逻辑,比如小部件。

我来自 ruby 背景,提取所有存储逻辑相对简单,设置一个 ruby 变量,字面意思是 class 事件并使用该变量无论我在哪里使用 Event.我可以在打字稿中做类似的事情吗?是否有另一种机制可以让我将这个 class 的大部分重新用于其他东西,比如 Widget?

理想情况下,我的 EventsStorage class 变得非常轻巧,我不只是包装对 this.some_storage_module.get_ids()this.some_storage_module.insert_new_objs() 的调用——它们必须是 copy/pasted对于我需要的所有其他实例。

像这样:

export class EventsStorage {  // extends BaseStorage (maybe??)
  constructor(){
    super(Event, 'events'); // or some small set of magical args
  }
}

这是现有的class:

import { Injectable } from '@angular/core';
import { Storage }    from '@ionic/storage';

import { Event }      from '../classes/event';

// EventsStorage < EntityStorage
// - tracks local storage info
// - a key to an array of saved objects
// - a query() method that returns saved objects

@Injectable()
export class EventsStorage {
  base_key: string;
  ids_key: string;

  constructor(
    private storage: Storage
  ){
    this.base_key = 'event';
    this.ids_key = [this.base_key, 'ids'].join('_');
  }

  get_ids(): Promise<any>{
    return this.storage.ready().then(() => {
      return this.storage.get(this.ids_key).then((val) => {
        if(val === null){
          return [];
        } else {
          return val;
        }
      });
    });
  }

  insert_new_objs(new_objs: any): Promise<any>{
    return new_objs.reduce((prev: Promise<string>, cur: any): Promise<any> => {
      return prev.then(() => {
        return this.storage.set(cur._id, cur.event);
      });
    }, Promise.resolve()).then(() => {
      console.log('saving event_ids');
      return this.storage.set(this.ids_key, new_objs.map(obj => obj._id));
    });
  }

  update(events: Event[]): Promise<any> {
    let new_objs = events.map((event) => {
      return {
        _id: [this.base_key, event.id].join('_'),
        event: event
      };
    });

    return this.insert_new_objs(new_objs);
  }

  query(): Promise<Event[]>{
    let events = [];
    return this.get_ids().then((ids) => {
      return ids.reduce((prev: Promise<string>, cur: string): Promise<any> => {
        return prev.then(() => {
          return this.get_id(cur).then((raw_event) => {
            events = events.concat([raw_event as Event]);
            return events;
          });
        });
      }, Promise.resolve());
    });
  }

  get_id(id: string): Promise<Event>{
    return this.storage.get(id).then((raw_event) => {
      return raw_event;
    });
  }
}

在我看来,您想使用泛型。您基本上是在要存储的所有内容之间定义一些基本接口,并且您的代码应该依赖于该接口。据我所知,在你的代码中只使用 id 属性.

所以看起来有点像这样

import { Event }  from '...';
import { Widget } from '...';
interface HasId{
    id: string;
}

class ItemsStorage<T extends HasId> {
 ....
 get_id(id: string): Promise<T>{
    ...
 }
}

const EventStorage = new ItemsStorage<Events>(storage);
const WidgetStorage = new ItemsStorage<Widget>(storage);
const ev = EventStorage.get_id('abc');     //type is Promise<Event>
const wd = WidgetStorage.get_id('def');    //type is Promise<Widget>

您可以阅读有关泛型的更多信息here

编辑: 1 - 关于 subclassing - 通常不太可取。如果您的 ItemsStorage class 在处理事件和小部件时需要不同的行为,那么 subclassing 是您的解决方案。但是,如果您对每个 class 都有相同的行为,那么人们可能会称您的代码为 generic,使用泛型会更好。