Exteding a class from lazy loaded script - javascript

I have a ts class that extends another class, but the parent class is inside of a js lib that is loaded lazily so it is not recognized by ts after transpiling (everything is angular cli default):
TSClassFile
export class TSClass extends JSClassFromScriptFile {
constructor() {
super();
}
}
AngularComponent Using TsClass
#Component({...})
export class AngularComponent {
testTsClass: TsClass;
constructor() {
// loads scriptFile and initiates test param
this.loadScript('scriptFile').then( res => {
this.testTsClass = new TsClass();
});
}
// Adds script tag to head el with src of scriptName
loadScript(scriptName): Promise {
...
}
}
I found a "solution" which I'm not happy with because it has no reusability whatsoever :
...
testTsClass: any;
constructor() {
this.loadScript('scriptFile').then( res => {
class TSClass extends JSClassFromScriptFile {
constructor() {
super();
}
}
this.testTsClass = new TsClass();
});
}
...
so any more elegant way is much appreciated.

Related

How can I inherit class in javascript and use static method?

I have this simple js service that I want to use as a static method. Right now here's my code:
class BaseService {
constructor() {
this.baseUrl = '';
}
list(params) {
return axios.get(`${this.baseUrl}`, { params }).then((response) => response.data);
}
//(...)
}
class DimensionService extends BaseService {
constructor() {
super();
this.baseUrl = '/api/dimensions';
}
}
//usage
let service = new DimensionService();
service.list();
and I would rather use it like that:
DimensionService.list()
the problem is I cannot inherit baseUrl, because in the static method the constructor is never called. What can I do?

JS: TypeError: Class extends value <ClassName> is not a constructor or null

I write UI tests using PageObject Pattern (NodeJS + Webdriverio) and I have a base class (BasePage), a page class(MyPage), a popup component class(PopupComponentClass) with multipurpose behaviour, a popup class with a specific implementation(SpecificPopupComponentClass). I need to extend SpecificPopupComponentClass from PopupComponentClass.
page.js:
export default class BasePage {
get BASE_URL() {
return "https://url.com";
};
...some methods...
}
my.page.js:
import BasePage from "../page";
class MyPage extends BasePage {
constructor() {
super();
};
get URL() { return `${this.BASE_URL}/some/path` };
get title() { return $("h1") };
orderRandomTariff() {
...some actions...
};
}
export default new MyPage ();
popup.component.page.js:
import BasePage from "../pages/page";
class PopupComponent extends BasePage{
constructor() {
super();
};
get title() { return $("h1") };
}
export default new PopupComponent();
specific.popup.component.js:
import PopupComponent from "./popupFragment";
class SpecificPopupComponent extends PopupComponent {
constructor() {
super();
};
get popupStreetInput() { return $(".//div[#class='checkAddress']//*[./*[contains(text(),'Street')]]//input") };
fillStreet(street) {
...some actions with this.popupStreetInput...
};
}
export default new SpecificPopupComponent();
...and trying to use it in test.js:
import MyPage from "../../../../pages/my.page";
import SpecificPopupComponent from "../../../../fragments/specific.popup.component";
const myPage= MyPage ;
const popup = SpecificPopupComponent ;
describe("Test", () => {
before(() => {
myPage.open();
});
it("Check", () => {
popup.fillStreet("Street");
});
});
but I'm getting an error: "TypeError: Class extends vlaue #PopupComponent is not a constructor or null".
I suspect this is due to circular dependencies, but I can't understand, what I need to do to fix that.
It seems the issue here is how you're exporting the base class. You're instantiating it instead of just exporting the class you'll inherit from. It should be like this:
export default class PopupComponent extends BasePage {
constructor() {
super();
};
get title() { return $("h1") };
}
And then create the instance when you're going to use it
var myPage = new MyPage()
var popup = new SpecificPopupComponent()
myPage.open()
popup.fillStreet('street')
What you're doing there is equivalent to doing this:
class SpecificPopupComponent extends new PopupComponent() {
// ... what am I? 🤔
}
I suspect this is due to circular dependencies
You can validate or reject your suspects by copying all the code into the test file in the correct order without using imports. But I don't think it's an circular dependency
I created this Plunker to remove the usage of imports and prove this.

How to automatically load files that contain specific decorators in a node project

I have created a decorator, in Project A (the main library) and would like to have all of those decorators automatically loaded when the app starts in Project B (the project using Project A). Is there anyway of doing this?
index.ts looks like this:
export function MyDecorator<T extends Controller>() {
return (target: new () => T) => {
// Do stuff with the decorator
}
}
const server = http.createServer((req, res) => {
})
server.listen(8080)
Is there something that I can do to automatically execute #MyDecorator() on all classes in Project B without Project B having to do so?
MyClass1.ts
import { MyDecorator } from 'project-a'
#MyDecorator()
export class ProjectBClass1 {}
MyClass2.ts
import { MyDecorator } from 'project-a'
#MyDecorator()
export class ProjectBClass2 {}
I assume you mean creating instances by load .
Also I'm not sure if that is an elegant solution but here is my suggestion:
Create a class that has a static method:
class ControllerCreator {
private static constrollerInstances: any = []
private static controllerConstructors : any = [];
static registerControllerClass(ctor: any) {
ControllerCreator.controllerConstructors.push(ctor);
}
static createInstances() {
ControllerCreator.controllerConstructors.forEach(
ctor => constrollerInstances.push(new ctor()) // pushing them to static array to not lose
)
}
}
In your decorator you should register your controller constructor:
export function MyDecorator<T extends Controller>() {
return (target: new () => T) => {
// Do stuff with the decorator
class newClass extends target {
// ...
}
ControllerCreator.registerControllerClass(newClass);
}
}
And finally at some point you should call:
ControllerCreator.createInstances();

ES6: How to Add a Static Class Property [duplicate]

Read the example below*, but don't pay too much attention to the EventEmitter inheritance, please – it just shows the utility of the class syntax.
I realize that the example is not correct ES2015, since there no such thing as a static class statement.
What would be the most syntactically lean way to make something like this work in ES2015?
class App extends EventEmitter {
addPage(name) {
this[name] = new App.Page;
this.emit("page-added");
}
static class Page extends EventEmitter {
constructor() {
super();
this._paragraphs = [];
}
addParagraph(text) {
this._paragraphs.push(text);
this.emit("paragraph-added");
}
}
}
Should I just split it up and use a class expression, like below? Seems less elegant.
class App extends EventEmitter {
addPage(name) {
this[name] = new App.Page;
this.emit("page-added");
}
}
App.Page = class extends EventEmitter {
constructor() {
super();
this._paragraphs = [];
}
addParagraph(text) {
this._paragraphs.push(text);
this.emit("paragraph-added");
}
};
Should I just split it up and use a class expression?
Yes, that's the way to go. If you insist on using a declaration, you'd have to make a App.Page = Page assignment afterwards.
You could have your class created inside addPage. It will create the "abstraction" I suppose you're looking for, but you'll pay in performance (each addPage call will be slower.
'use strict';
class EventEmitter {
emit(s) {
alert(s);
}
}
class App extends EventEmitter {
addPage(name) {
class Page extends EventEmitter {
constructor() {
super();
this._paragraphs = [];
}
addParagraph(text) {
this._paragraphs.push(text);
this.emit("paragraph-added");
}
}
this[name] = new Page;
this.emit("page-added");
}
}
var app = new App;
app.addPage("myPage");
app.myPage.addParagraph("Some content");
Alternatively, have both classes defined in a module, and only export the App class thus preventing pollution of the global scope.

Inheritance method call triggers Typescript compiler error

I am having an issue with webstorm typescript compiler. I have the following classes
export class rootData{
id:string
//...
constructor(){
//...
}
insert = ():Promise<any> =>{
//...
}
}
class child extends rootData {
//...
constructor(){
super();
}
insert = ():Promise<any> => {
return super.insert();
}
}
So typing "super", I see all rootData public methods in the intellisense. But after setting super.insert(), I get the following error :
TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword
Tried in TS playground, it is working (simplified version thought).
Thanks for your help.
EDIT: After checking the compiled javascript, the call of the super method is there. So the compiler gives an error but compiles...
Because super calls are redirected to the prototype you cannot use a property and need to use a method i.e. can't use = ()=>.
Fixed code:
export class rootData{
id:string
//...
constructor(){
//...
}
insert():Promise<any>{
//...
}
}
class child extends rootData {
//...
constructor(){
super();
}
insert():Promise<any> {
return super.insert();
}
}
You could create an "internal" method that is protected that actually performs the logic. Since you can't call it outside of the class, the this will always be in the correct context.
export class rootData{
id:string
//...
constructor(){
//...
}
insert = ():Promise<any> =>{
return this.insertInternal();
}
protected insertInternal():Promise<any>{
//...
}
}
class child extends rootData {
//...
constructor(){
super();
}
protected insertInternal():Promise<any> {
return super.insertInternal();
}
}
You can view a TypeScript Playgound version of it here.

Categories

Resources