11

I'm currently implementing the static land specification (an alternative of fantasy land). I want to not only use plain objects as types but also ES2015 classes with static methods. I've implemented these static methods as arrow functions in curried form instead of normal functions. However, this isn't possible with ES2015 classes:

class List extends Array {
  static map = f => xs => xs.map(x => f(x))
  static of = x => [x]
}

My map doesn't need its own this, because it is merely a curried function on the List constructor. To make it work I have to write static map(f) { return xs => xs.map(x => f(x)) }, what is very annoying.

  • Why can't I use arrow functions along with an assignment expression in ES2015 classes?
  • Is there a concise way to achieve my goal anyway?
  • 1
    If everything's static, why the `extends Array`? – T.J. Crowder Aug 22 '16 at 12:51
  • possible duplicate of https://stackoverflow.com/questions/32545495/es6-class-instance-properties? – Bergi Aug 22 '16 at 12:56
  • @T.J. The idea is to make an existing library static land compatible. So there will be classes with non-static properties, which must be extended. –  Aug 22 '16 at 12:57

1 Answers1

15

Why can't I use arrow functions along with an assignment expression in ES2015 classes?

Because that's just not how the ES2015 class syntax is designed — for now, see under the line below.

Is there a concise way to achieve my goal anyway?

It's not clear to me that you want classes at all, just an object:

const List = {
  map: f => xs => xs.map(x => f(x)),
  of:  x => [x]
};

(You've said that extending is important to what you're doing.)

But if you want List to extend Array (e.g., you will have instances) but then add these statics to it, you'll need a two-step:

let List = Object.assign(
  class List extends Array { },
  {
    map: f => xs => xs.map(x => f(x)),
    of:  x => [x]
  }
);

console.log(List.of(42)); // [42]

If you want them non-enumerable or non-configurable, etc., you'll want Object.defineProperties rather than Object.assign; I'll leave that as an exercise for the reader...


There's a Stage 3 proposal for class "fields," including static fields, which is being actively implemented by JavaScript engine builders. (And you can use it now via tools like Babel.) It provides static field declaration syntax within the class, almost exactly the way you showed them:

// Not in the language yet, but at Stage 3 and shipping without
// any flags in V8 (for instance, in Chrome)
class List extends Array {
  static map = f => xs => xs.map(x => f(x));
  static of = x => [x];
}

console.log(List.of(42)); // [42]

Note: There's a standard Array.of method, so I wouldn't add an incompatible of to that List.

Finally, I should note that unless there's some reason they have to be arrow functions, ES2015's class syntax supports static methods:

// ES2015+
class List extends Array {
  static map(f) {
    return xs => xs.map(x => f(x));
  }
  static of(x) {
    return [x];
  }
}

console.log(List.of(42)); // [42]
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875