3

Sorry if this is bizarre or anti-pattern.

Suppose I have a static method on a child class, e.g (heavily simplified for readability)

class User extends Model {
  //...
    static getAll(){
      db.execute('SELECT * FROM users');
    }
}

Since I have multiple models I might want a getAll method on, it seems ideal to define getAll on the Model class, which makes reference to a tableName class variable. Ideally it would look something like

class Model {
  static getAll(){
    db.execute(`SELECT * FROM ${this.tableName}`);
  }
}
//...
User.tableName = 'users';

This won't work, because ES6 doesn't like you defining class variables like that. There are a number of workarounds, such as adding a tableName parameter in the parent then applying users to it in User:

class Model {
  static getAll(tableName) {
    db.execute(`SELECT * FROM ${tableName}`)
  }
}
//...
class User extends Model{
  static getAll() {
    Model.getAll('users')
  }
}

but explicitly re-writing inherited functions for all of a class's children like this seems dreadfully anti-pattern. Other solutions I've seen (such as using static functions to return constants, or wrapping both classes in an object) are kinda ugly and not a pattern I want to commit to unless I have to. So I'm looking for an easily-readable ES6 pattern that lets me do the following:

  1. Inherit static methods from a parent class.
  2. Refer to class variables (or something equivalent) in the parent class, such that they can be specified for different child classes
  3. Not have to explicitly refer to inherited methods in the child class.

Does such a solution exist, or is it worth doing it the 'hard way' in ES5?

7
  • Could something like this fiddle be at least a little better? Commented Nov 27, 2017 at 5:51
  • It doesn't solve the problem of having to account for all of the parent's methods in each of the children, which is the main thing I'm trying to avoid. Commented Nov 27, 2017 at 5:56
  • I know, that's why I put it as a comment :p because I know it isn't an answer Commented Nov 27, 2017 at 5:56
  • Rereading your question, I think I misinterpreted it in my answer below. From second look, it sounds like you would want to use Model.getAll as opposed to User.getAll, right? If that's the case, I can't think of a way this is doable w/o a hack Commented Nov 27, 2017 at 6:11
  • @ChristianSantos that's right - I want to use Model's getAll method without having to redefine it on User. Fairly sure this is directly doable in Ruby and other OOPLs. Is there maybe some other way of effectively doing the same thing while keeping my DRY? Perhaps without ES6 class inheritance? Commented Nov 27, 2017 at 6:16

3 Answers 3

2

This won't work, because ES6 doesn't like you defining class variables like that.

What makes you think that? User is a function like any other function. Static methods become properties of that function. Assigning a property directly to User works just fine.

class Model {
  static getAll() {
    return `SELECT * FROM ${this.tableName}`;
  }
}

class User extends Model {}
User.tableName = 'users';
class Product extends Model {}
Product.tableName = 'product';


console.log(User.getAll());
console.log(Product.getAll());

Sign up to request clarification or add additional context in comments.

2 Comments

Huh. This wasn't working before - presumably due to an error elsewhere. Thanks though!
Even better use class User extends Model { static tableName = 'users'; }
1

Although this feels slightly hackish -- there is a way to achieve what you need using these two facts about ES6 classes:

  • We can define static getters using static get in the class definition -- and these getters will function as static properties.
  • Static methods can use this to call other static methods. This means your parent class's static method can use this to refer to a static method in your child class.

Altogether, the code would look like this:

class Model {

    static getAll() {
        console.log(this.tableName); // will refer to child's static getter
    }

    static randomFunc() {
        console.log(this.tableName); // will also refer to child's static getter
    }
}

class User extends Model {
    
    static get tableName() {
        return "users"; // define child's tableName here
    }
}

class Worker extends Model {
    
    static get tableName() {
        return "workers"; // define child's tableName here
    }
}

User.getAll(); // prints users
User.randomFunc(); // prints users

Worker.getAll(); // prints workers
Worker.randomFunc(); // prints workers

1 Comment

This looks like the least painful way of doing this: I didn't know about static getters, but it looks like they're only marginally different to proper class variables. It does work for my code, thanks!
0

A simplification of the good solution of @Christian Santos

class Model {

    static getAll() {
        console.log(this.tableName); // will refer to child's static var
    }

    static randomFunc() {
        console.log(this.tableName); // will also refer to child's static var
    }
}

class User extends Model {
    static tableName = "users";
}

class Worker extends Model {
    static tableName = "workers";
}

User.getAll(); // prints users
User.randomFunc(); // prints users

Worker.getAll(); // prints workers
Worker.randomFunc(); // prints workers

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.