Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Prevent Inheritance of Specific Method?

Say I have two classes, A and B. B extends A and therefore inherits all of its methods. I can override them if I want to as well. My question is whether or not I can prevent B from inheriting a specific method of A. What I've tried so far looks like this.

// setup
class A {
  constructor(x) {
    this.x = x;
  }

  valueOf() {
    return this.x;
  }

  toString() {
    return `{x:${this.x}}`;
  }
}

class B extends A {
  constructor(x) {
    super(x);
    delete this.valueOf;
  }
}

delete B.prototype.valueOf;

// example
const a = new A(42);
const b = new B(42);

// should work
console.log(a.valueOf());
// should throw TypeError, not a function
console.log(b.valueOf());
like image 399
kamoroso94 Avatar asked Jul 17 '17 19:07

kamoroso94


2 Answers

A couple folks have already told you how to solve your issue. Now I'd like to try to convince you to not do it. ;-)

Inheritance is supposed to model an IS-A relationship. Or, more specifically, an IS-SUBSTITUTABLE-FOR-A relationship. That's the Liskov Substitution Principle (the "L" in SOLID).

Any piece of code that is expecting to operate on an "A" object is supposed to be able to be given a "B" object instead ("A" is substituted for a "B") and everything should still just work. But if "B" is missing a method, if it doesn't provide the full interface of "A", then it isn't substitutable anymore, and odds are very good this isn't the right situation to use inheritance.

like image 153
Jeff M Avatar answered Oct 02 '22 05:10

Jeff M


Actually valueOf is bad example because every object gets one from Object.prototype. Try console.log(({}).valueOf())

But you could do a trick by hiding this property

// setup
class A {
  constructor(x) {
    this.x = x;
  }

  valueOf() {
    return this.x;
  }

  toString() {
    return `{x:${this.x}}`;
  }
}

class B extends A {
   get valueOf() { return undefined }
}

class C extends A {
}

Object.defineProperty(C.prototype, 'valueOf', {})


// example
const a = new A(42);
const b = new B(42);
const c = new C(42);

// should work
console.log(a.valueOf());
// should throw TypeError, not a function
try {
  console.log(b.valueOf());
} catch (e) {
  console.log(e.message)
}



try {
  console.log(c.valueOf());
} catch (e) {
  console.log(e.message)
}
like image 39
Yury Tarabanko Avatar answered Oct 02 '22 05:10

Yury Tarabanko