如何使这个 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,使用泛型会更好。
我有这个 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,使用泛型会更好。