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

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?

Related

javascript, remove common parameter from child classes

I have defined a Axios base class like this
class BaseService {
constructor(baseurl, defaultHeaders, errorCallback) {
const options = {
baseURL: baseurl,
headers: defaultHeaders
};
this.fetcher = axios.create(options);
}
}
class serviceA extends BaseService {}
class serviceB extends BaseService {}
then I am creating multiple instance like this
const serviceA = new ServiceA(IVA_URL,defaultHeaders,setloggedInUser);
const serviceB = new ServiceB(IVB_URL,defaultHeaders,setloggedInUser);
Now I want to remove defaultHeaders,setloggedInUser these two or more common parameters from every service constructor function.
Also defaultHeaders will be available at run time.
You can use static members. set default value once and use multiple times.
class BaseService {
static defaultHeaders;
static defaultCallback;
constructor(baseurl) {
const options = {
baseURL: baseurl,
headers: BaseService.defaultHeaders
};
this.fetcher = axios.create(options);
}
}
class serviceA extends BaseService {}
class serviceB extends BaseService {}
and then:
BaseService.defaultHeaders = defaultHeaders;
BaseService.defaultCallback = setloggedInUser;
const serviceA = new ServiceA(IVA_URL);
const serviceB = new ServiceB(IVB_URL);

How to mock class constructor and static function with jest

I want to mock simultaneously both my default exported class constructor and a static function of the said class that instantiate and returns an instance of the said class(singleton). How can I do it with Jest. Here is a code sample:
export default class MyClass {
private static instance: MyClass;
private data: any;
constructor() {
this.data = ...DefaultData...;
}
public static getInstance(): MyClass {
if (!MyClass.instance) {
MyClass.instance = new MyClass();
}
return MyClass.instance;
}
public setData(newData){
this.data = newData;
}
public methodA(){...doSomethingWith_this.data}
}
Also as requested heres an example of my test where I only have mocked the 'getInstance' method.
import MyClass from 'path/to/MyClass';
jest.mock('path/to/MyClass', () => {
const instance = {
methodA: jest.fn(),
setData: jest.fn()
};
return {
__esModule: true,
default: {
getInstance: () => instance
}
};
});
describe('SystemUnderTest', () => {
it('test for in code instantiation', ()=>{});
it('test for singleton instance', ()=>{});
})
Finally the error I get when running the tests is this
_MyClass.default is not a constructor
Change this to MyClass. A static variable is a class property that is used in a class and not on the instance of the class.
export default class MyClass {
private static instance: MyClass;
constructor() {}
public static getInstance(): MyClass {
if (!MyClass.instance) {
MyClass.instance = new MyClass();
}
return MyClass.instance;
}
}
This is how a singleton works based on your code example. You do not have any example from Jest therefore I must refer to https://stackoverflow.com/help/how-to-ask

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();

Exteding a class from lazy loaded script

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.

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