John Hartman
John Hartman

Reputation: 315

Can I use class variables in the parent class's static methods in ES6?

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?

Upvotes: 3

Views: 2008

Answers (3)

alex
alex

Reputation: 955

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

Upvotes: 0

Felix Kling
Felix Kling

Reputation: 817138

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

Upvotes: 2

Christian Santos
Christian Santos

Reputation: 5456

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

Upvotes: 1

Related Questions