Jie Wang
Jie Wang

Reputation: 680

In Typescript, create extension method for class that from library

I want to add some method to existed class that come from library.

Known some basic type like String, Element can extension via interface and add it's prototype.

interface String {
 extFunc():Function;
}

String.prototype.extFunc = function () {
  //blabla
};

"a".extFunc();

I also find the way to add extension method of Observable<T>.

declare module 'rxjs/Observable' {
  interface Observable<T> {
    foo: String;
  }
}
Observable.prototype.foo= "bar";
console.log(Observable.of("a").foo);

But when i try to do same thing to NavController(an lib from ionic), it will override entire NavController to the interface that i declare.

declare module 'ionic-angular' {
  interface NavController {
    replace(page: Page): Promise<any>;
  }
}
navCtrl.replace(...); //ok
navCtrl.push(...); //original function => "not exist"

Does anyone know what is best way to add extension method to those class? thanks~

Edit: There is actual code

import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';

import {GuidePage} from '../guide/guide.component';

@Component({
  selector: 'page-home',
  templateUrl: 'home.component.html'
})
export class HomePage {
  pageName = "home";

  // navCtrl is come from angular2's Dependency Injection,
  // it may not suitable to extend NavController
  constructor(public navCtrl: NavController) {}

  gotoGuide(): void {
    //wanna replace this
    this.navCtrl.push(GuidePage).then(() => {
      let index = this.navCtrl.getActive().index;
      this.navCtrl.remove(index - 1);
    });

    //with this custom extension method 
    //this.navCtrl.replace(GuidePage);
  }
}

Upvotes: 8

Views: 5595

Answers (2)

Jie Wang
Jie Wang

Reputation: 680

Ok, I reference to this answer and solve my question with the following code.

In polyfill.ts

import {Page} from 'ionic-angular/navigation/nav-util';
// the class we wanna create extension method
import {NavController} from 'ionic-angular/navigation/nav-controller';
// ionic provide this as NavController
import {NavControllerBase} from 'ionic-angular/navigation/nav-controller-base';

// add extension method on both class via interface
declare module "ionic-angular/navigation/nav-controller" {
  interface NavController {
    // replacePage?: typeof replacePage;
    replacePage(page: Page, data?: any);
  }
}
declare module "ionic-angular/navigation/nav-controller-base" {
  interface NavControllerBase {
    // replacePage?: typeof replacePage;
    replacePage(page: Page, data?: any);
  }
}

// define extension method 
function replacePage(this: NavController, page: Page, data?: any): Promise<any> {
  return this.push(page, data).then(() => {
    let index = this.getActive().index;
    this.remove(index - 1);
  });
}

// finally add this function to the class that ionic provide
NavControllerBase.prototype.replacePage = replacePage;

usage:

constructor(private navCtrl: NavController)
foo(){
    this.navCtrl.replacePage(HomePage, {nextPage: OtherPage});
}

This way to add extension method on other class, wish this help someone after.

Upvotes: 7

Kokodoko
Kokodoko

Reputation: 28128

Your question is how to extend a class, but your code shows interfaces.

How to extend a class from a library:

class LibraryThing {
    // this is a class from a library
    doSomething(){
    }
}

class MyThing extends LibraryThing {
    // here you can add your own methods to the existing class
    doMyThing(){
    }
}

Now you can create a MyThing instance which will have all the library methods and your own methods:

let t = new MyThing();
t.doSomething();
t.doMyThing();

If you want to use interfaces you can simply implement them. You can implement existing library interfaces and complement that with your own interfaces

interface LibraryInterface {}
interface MyOwnInterface {}

class CoolThing implements LibraryInterface, MyOwnInterface {
    // this class uses methods from the library interface and your own
}

You do not need prototype when working with typescript.

EDIT

I have not tried if this works, but instead of passing the navcontroller in the constructor, you can pass your own class that extends navcontroller.

import {Component} from '@angular/core';

import {CustomController} from '../mystuff/customcontroller';    
import {GuidePage} from '../guide/guide.component';

@Component({
  selector: 'page-home',
  templateUrl: 'home.component.html'
})
export class HomePage {
  pageName = "home";

  // here we receive our own CustomController
  constructor(public navCtrl: CustomController) {}

  gotoGuide(): void {
    this.navCtrl.myOwnCustomStuff();
  }
}

In CustomController you can import Navcontroller and extend it:

import { Injectable } from '@angular/core'
import {NavController} from 'ionic-angular'

@injectable()
export class CustomController extends NavController {
}

I haven't tested if this is allowed for an ionic component though!

You also have to register your own new injectable as a provider for angular DI, follow the steps in your link

Upvotes: 1

Related Questions