Wonder if anyone can help?
I'm trying to call a parent's constructor or at a minimum get a reference to the parent class in some way without hardcoding anything.
class A {
static foo(options) {
parent::__construct(options); <- this is how you would get the parent in php
}
}
class B extends A {
}
Is this possible?
In a javascript class (and OOP in general), a static method is not part of an instance and therefore the object it resides in does not have a constructor.
You should avoid using static method for this sort of thing and use a standard constructor and call super() to call the parent constructor.
class A {
constructor(options) {
console.log('Options are:');
console.log(options);
}
}
class B extends A {
constructor(options) {
super(options);
}
}
const item = new B({item1: 'abc'});
Further reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
You can use super() to call parent constructor
class A {
constructor() {
console.log('I\'m parent ');
}
foo(){
console.log('Class A: Called foo');
}
}
class B extends A {
constructor() {
super();
}
foo(){
super.foo()
}
}
const b = new B();
b.foo();
Related
I have some class for crud API service class
I want to extend it but spear few properties
for exam this is my class
class Parent {
public propertyToKeep: any;
public propertyToDelete: any;
constructor() { }
}
this is the child class
class Child extends Parent {
constructor() {
super();
}
}
Another file
where I don't want to see and get access to
export class comeComponent {
constructor(private child: Child) {
this.child.propertyToKeep // work
this.child.propertyToDelete // error and I can't even see it
}
}
I just came across the same use case as you and here's how I did it:
const Omit = <T, K extends keyof T>(Class: new () => T, keys: K[]): new () => Omit<T, typeof keys[number]> => Class;
Then you can use it like so :
class Child extends Omit(Parent, ['propertyToDelete']) {}
As you can see child only has one property now (it also works with methods).
The package from #nestjs/swagger has some nice helpers if you're dealing with a NestJS API. Their implementation is more complex so I guess they are keeping other stuff like their own property decorators (I am pretty new to Typescript so maybe I miss the point of all they are doing).
P.S: French guy tried to answer for first time with imperfect English so please be kind ^^
Here is one way to do it:
class Parent {
propertyToKeep = 'hi';
propertyToDelete = 'bye';
constructor() {}
}
class Child extends Parent {
constructor() {
super();
delete this.propertyToDelete;
}
}
const myObject = new Child();
console.log(myObject);
/* OUTPUT:
{
"propertyToKeep": "hi"
}
*/
You need to use Object.defineProperty function, for make a restriction in descriptor, enumerable to false and getter, setter with specific condition, here a complete example:
//A small example of how to make an invisible property in Child class.
class Parent{
constructor(){
this.propertyToKeep = "Visible";
this.propertyToDelete = "Not visible in subclass child";
}
}
Object.defineProperty(Parent.prototype, "propertyToDelete", {enumerable: false,
configurable: true,
get: function(){
if(!(this instanceof Child)){
return this._propertyToDelete;
}
},
set: function(v){
if(!(this instanceof Child)){
this._propertyToDelete = v;
}
}});
Object.freeze(Parent.prototype);
class Child extends Parent {
constructor() {
super();
}
}
//console.log(Child.prototype);
let chd = new Child();
console.log("Child: --------------------------------");
console.log(chd);
console.log(chd.propertyToDelete); //Undefined
console.log("Parent: -------------------------------");
let prt = new Parent();
console.log(prt);
console.log(prt.propertyToDelete); //"Not visible in subclass child"
/*let chdObj = Object.getOwnPropertyDescriptors(Child.prototype);
console.log(chdObj);*/
class SomeComponent{
#child;
constructor(child) {
this.#child = child;
console.log(this.#child); //{propertyToKeep: "Visible"}
console.log(this.#child.propertyToKeep /*work*/);
console.log(this.#child.propertyToDelete /*undefined*/);
}
}
//Now i will invoke SomeComponent
console.log("SomeComponent: -------------------------");
let sc = new SomeComponent(new Child());
That's not possible. If you declare an attribute in a parent class, you can't restrict his visibility in a child class.
From the model design point of view, that doesn't make sense as well. The problem you are exposing here indicates that your class hierarchy is not well designed and you must rethink and redesign it.
I have two classes in javascript a, b. Class b extends a. Class a calls method in constructor. I wanna override this method in b class. How to call overridable method? when I added to class a, to constructor this.method(), it always calls method from a class.
class a {
constructor() {
this.method();
}
method() {
alert("a");
}
}
class b extends a {
constructor() {
super();
}
method() {
alert("b");
}
}
If you don't know in advance whether the instance is of the subclass or superclass, you can make sure the superclass calls its own method by having the superclass reference itself explicitly:
A.prototype.method.call(this);
class A {
constructor() {
A.prototype.method.call(this);
}
method() {
console.log("a");
}
}
class B extends A {
constructor() {
super();
}
method() {
console.log("b");
}
}
const b = new B();
class A {
constructor(){
this.method()
}
method(){
alert("a");
}
}
class B extends A {
constructor(){
super()
}
method(){
alert("b");
}
}
new B();
The following code will alert undefined
class Parent {
field: string
constructor() {
alert(this.field)
}
}
class Child extends Parent {
field = 'child'
}
new Child() #=> undefined
whereas, the following alerts 'child' as expected
class Parent {
field: string
constructor() {
alert(this.field)
}
}
class Child extends Parent {
field = 'child'
constructor() {
// without referencing this.field before super(), this.field stays undefiend
this.field
super()
}
}
new Child() #=> 'child'
Is there any ways to accomplish the following conditions?
omit the whole Child's constructor declaration like the first example
grab the member variable in Child class?
What jumps to mind is:
class Parent {
constructor(public field: string) {
alert(this.field)
}
}
class Child extends Parent {
constructor() {
super('child');
}
}
new Child() #=> 'child'
This doesn't meet your conditions but I feel it is fairly compact.
Well you could defer the property access to a micortask:
class Parent {
field: string
constructor() {
Promise.resolve().then(() => {
alert(this.field)
};
}
}
But while that fullfills your conditions, it is ... still the wrong approach. Pass field as a constructor argument, as other answers show.
There's no way to accomplish your conditions, i'm pretty sure.
Grabbing the member variable in sub class happens after the base class constructor runs, and calling super() must be the first statement in a sub class constructor.
class Child extends Parent {
field = 'child';
}
// the above is equal to:
class Child extends Parent {
constructor(){ super(); this.field = 'child'; }
}
And this would cause error:
class Child extends Parent {
constructor(){
this.field = 'child'; // ERROR!
super();
}
}
I'm creating a #Component decorator that intercedes the constructor of a class to carry out some work after construction. As can be seen in the following code, the work is implemented in an init method.
export function Component (Cls) {
function Class (...args) {
let self = new Cls (...args); // (1)
init (self, ...args);
return self;
}
Class.prototype = Cls.prototype;
return Class;
}
When I test this code on a regular class all works fine. This is a working example:
class Base { ... }
#Component
class Core extends Base {
constructor () {
super (); // init is invoked
}
fx () { console.log ('Core.fx') }
fy () { console.log ('Core.fy') }
}
Nevertheless, when I try to decorate a web component a TypeError: Illegal constructor message is obtained.
#Component
class Core extends HTMLElement {
constructor () {
super ();
}
fx () { console.log ('Core.fx') }
fy () { console.log ('Core.fy') }
}
customElements.define ('x-core', Core);
let coreX = document.createElement ('x-core');
document.body.appendChild (coreX);
I realise the problem is that HTMLElement's do not support direct construction through new operator - see (1) on first listing - but I need a procedure to decorate constructor of any class even though they are custom elements.
Some Idea?
Working Settings: Chrome 68 ยท Babel 7.0.0-beta.51 with babel-plugin-transform-decorators-legacy
You can return a class to avoid direct new.
function Component(cls) {
class c extends cls {
constructor() {
super()
console.log(this)//init
}
}
return c
}
I am curious can I call a extended class and have it still import the things it needs specifically.
Welcome Class:
import { ErrorLevel } from './error-level.js';
export class Welcome extends ErrorLevel {
constructor() {
super();
}
}
Error-Level Class:
import { Notification } from 'aurelia-notification';
export class ErrorLevel {
static inject() {
return [Notification];
}
constructor(notification) {
this.notification = notification;
}
}
I know once I call super() it will call the extended class and pass in 0 arguments. Is there a way for my ErrorClass constructor to pull in Notification when I call super()?
super([arguments]); // calls the parent constructor.
super.functionOnParent([arguments]);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
Passing an argument in Welcome's super function calls the parent class constructor with that argument. You will see the log of this contains notification which is set to the argument we pass into super.
http://jsbin.com/raguqopesu/1/edit?js,console,output
class ErrorLevel {
constructor(notification) {
this.notification = notification;
}
}
class Welcome extends ErrorLevel {
constructor() {
super(Notification);
console.log(this);
}
}
const yo = new Welcome();
export class Welcome extends ErrorLevel {
constructor(notification) {
super(notification);
}
}