打字稿和多个类

Posted

技术标签:

【中文标题】打字稿和多个类【英文标题】:Typescript and multiple classes 【发布时间】:2017-08-19 03:29:49 【问题描述】:

我有一个组件类EventSchedulePage。它扩展了HandleStorageServiceabstract类,如下所示。你可以看到这个子类上有一个名为showInvalidTokenAlert()的方法。我必须分别调用这个方法并且每个组件(此方法向用户提供基于令牌的错误消息)。那么您能告诉我如何实现或重新设计我的类以适应这种情况吗?因为我不喜欢将showInvalidTokenAlert() 放在每个组件上。我想将该方法的实现保留在一个地方。

子类

    export class EventSchedulePage extends HandleStorageService 

    constructor() 
        super();
         

     showInvalidTokenAlert() 
       //show alert
      
  

抽象类

export abstract class HandleStorageService 
  result: string = '';

  constructor() 
  

【问题讨论】:

那你为什么不把showInvalidTokenAlert放到HandleStorageService呢? 该服务仅用于处理与存储相关的事情。这就是原因。@NitzanTomer 是 ionic 2 吗?如果是这样,您可以只注入具有该功能的提供程序.. Hmm.. 我试图找到一个基于 TS 的解决方案。但似乎唯一的解决方案是基于提供程序的注入。我会尝试。同时,你也可以回答这个问题。 @suraj 【参考方案1】:

您可以使用showInvalidTokenAlert() 函数创建一个单独的提供程序类

@Injectable()   
export class AlertProvider
  constructor()

  showInvalidTokenAlert()
  //...
  

在 app.module.ts 中将其设置为提供者,以防您需要作为单例

 @ngModule(
   //...
   providers:[
      AlertProvider,
   //..
   ]
 )

注入您需要的任何组件。

export class EventSchedulePage extends HandleStorageService 

   constructor(private alertProvider:AlertProvider) 
       super();
      
  //call this.alertProvider.showInvalidTokenAlert()

【讨论】:

我不能像这样在AlertProvider 中使用public navCtrl: NavController 吗? constructor(public alertCtrl: AlertController, public navCtrl: NavController) .它给出了这个错误Error: Uncaught (in promise): Error: Error in ./MyApp class MyApp - inline template:0:0 caused by: No provider for NavController! Error: DI Error.你知道为什么吗? github.com/driftyco/ionic/issues/9581 似乎是设计使然... 尝试在构造函数中使用@Inject(NavController) navController: NavController hmm.. 似乎是反模式,不是吗?我的意思是使用服务层来处理 UI 相关的事情?这就是为什么我尝试基于 TS 获得解决方案。您对此有何看法? 看起来是对的。我不建议这样做,因为您已经想扩展其他一些类了。“该服务仅用于处理与存储相关的事情。这就是原因。”您可以使用该方法并将 HandleStorageService 作为提供者..【参考方案2】:

您可以创建一个BasePage,并将所有共享代码放在那里。

import  Component, Injector  from '@angular/core';
import  AlertController, ... from 'ionic-angular';

@Component( selector: '', template: '<span></span>' )
export class BasePage 

    private _alertCtrl: AlertController;
    private _toastCtrl: ToastController;

    constructor(public injector: Injector)  

    // Get methods used to obtain instances from the injector just once
    // ----------------------------------------------------------------

    // AlertController
    public get alertCtrl(): AlertController 
        if (!this._alertCtrl) 
            this._alertCtrl = this.injector.get(AlertController);
        
        return this._alertCtrl;
    

    // ToastController
    public get toastCtrl(): ToastController 
        if (!this._toastCtrl) 
            this._toastCtrl = this.injector.get(ToastController);
        
        return this._toastCtrl;
    

    // ...

    // Helper methods
    // ----------------------------------------------------------------

    public showAlertMessage(message: string): void 
        let alert = this.alertCtrl.create( ... );
        alert.present();
    

    public showToastMessage(message: string): void 
        let toast = this.toastCtrl.create( ... );
        toast.onDidDismiss(() => 
            console.log('Dismissed toast');
        );
        toast.present();
    


关键是BasePage 从子类接收注入器的实例,因此您可以从中获取您需要的任何实例(例如您需要显示警报消息的AlertController 实例)。通过使用 get 方法,每个实例只会从注入器中获取一次。

然后在您应用的所有页面中:

import  Component, Injector  from '@angular/core';
import  BasePage  from '../path/to/base';

@Component(
    selector: 'page-home',
    templateUrl: 'home.html'
)
export class HomePage extends BasePage 

    constructor(public injector: Injector) 
        super(injector);
    

    public someMethod(): void 
        // You can use the methods from the BasePage!
        this.showAlertMessage('Your message...');
    

    public someOtherMethod(): void 
        this.showToastMessage('Another message');
    


这种方式超级容易添加一些辅助方法。

【讨论】:

我的问题是我已经在使用abstract 基类号(即HandleStorageService)?那是用于处理与存储相关的方法。那么如何在 TS 上扩展 2 个类? 将逻辑从HandleStorageService 移动到BasePage 怎么样?毕竟它也可以被认为是一个助手...... @Sampath 我已经编辑了答案以解决该问题,并向您展示在何处包含该方法。关于注入器,请记住,在 Angular 2 应用程序中,不仅有一个 single 注入器,而且还有一个层次结构的注入器(每个组件都有自己的注入器),因此我们需要将该实例发送到 BasePage 以能够使用正确的 AlertCtrl、ToastCtrl 等实例(如果我们不这样做,当您尝试使用 alertCtrl 显示消息时,它可能会使用不同的 alertCtrl 实例,并且可以在某些其他组件 - 或我们使用 Ionic 时的页面 -) 很好的例子。顺便提一下,对于 ionic 4,我们需要 async/await async showAlertMessage(message: string) let alert = await this.alertCtrl.create(...); alert.present(); 这是一个很棒的解决方案,非常感谢您发布它。我做了很多搜索才能找到这个,这比偷偷摸摸的服务要好得多。【参考方案3】:

hmm.. 似乎是反模式不是吗?我的意思是使用服务层来处理 UI相关的东西?这就是为什么我试图根据 TS.你对此有何看法? – Sampath

在控制器中处理它肯定更像 MVCS(模型-视图-控制器-服务)。但那是widely taken approach。

如果你想去,@suraj's answer 是我个人的推荐。

在控制器上处理警报当然是可能的。继续阅读。

event-schedule-page.service.ts

export class EventSchedulePage extends HandleStorageService 
  // ...
  foo() 
    if (!bar) 
      throw new Error('Something went wrong.');
    
    // ...
  

home.controller.ts

export class HomeController 
  // ...
  foo() 
    try 
      eventSchedulePageService.foo();
     catch (error) 
      window.alert(error); // Handle and UI display the error on the controller.
    
  

要跟进,您可以使用custom error classes 或单独的函数来抛出/处理您的错误。

【讨论】:

以上是关于打字稿和多个类的主要内容,如果未能解决你的问题,请参考以下文章

打字稿和 Knex

NodeJs 打字稿和模块问题

打字稿和正则表达式

打字稿和本机反应的 ForwardRef 错误

打字稿和传播运算符?

打字稿和嵌套解构