Flow: Support computed class properties

Created on 19 Aug 2016  路  9Comments  路  Source: facebook/flow

Computed properties in objects were added (#252), but computed properties in classes are still unsupported.

class Component {
  ["foo"]() {} // known
}
declare function foo(): string;
class Component {
  [foo()]() {} // unknown
}
ES2015+ enhancement feature request

Most helpful comment

In that case you can escape it using comments:

class Foo {

  constructor() {
    (this: any)[Symbol.iterator] = this._iterator;
  }

  _iterator(): Iterator<number> {
    return (function *() {
      yield 1;
      yield 2;
      yield 3;
    }())
  }
  /*::
  @@iterator(): Iterator<number> {
    throw new Error();
  }
  */
}

All 9 comments

@thejameskyle anything on this yet ?

@git-jiby-me Not yet, we'll update the issue when progress has been made

As this still isn't fixed, does anyone have a workaround?

I want to make an iterable class like this:

class Foo {
  [Symbol.iterator]() {
    // ...
  }
}

Is there any way to do it?

@callumlocke something like this:

class Foo {

  constructor() {
    (this: any)[Symbol.iterator] = this._iterator;
  }

  _iterator(): Iterator<number> {
    return (function *() {
      yield 1;
      yield 2;
      yield 3;
    }())
  }

  @@iterator(): Iterator<number> {
    throw new Error();
  }
}

it's a bit annoying, but if you use babel for transpiling, you cannot use the @@iterator() syntax :crying_cat_face:

In that case you can escape it using comments:

class Foo {

  constructor() {
    (this: any)[Symbol.iterator] = this._iterator;
  }

  _iterator(): Iterator<number> {
    return (function *() {
      yield 1;
      yield 2;
      yield 3;
    }())
  }
  /*::
  @@iterator(): Iterator<number> {
    throw new Error();
  }
  */
}

On a related note, does anyone have a work-around that would allow me to create an isIterable function that Flow could used to disambiguates the type of the argument I pass to it, for example:

if (isIterable(val)) {
  // Flow should know that `val` has type `Iterable<T>` on this branch of the guard
}
else {
  // Vs type `T` on this branch of the guard
}

doesn't work when isIterable is defined in an obvious way like this:

const isIterable = <T> (obj: T | Iterable<T>): boolean =>
  typeof (obj: any)[Symbol.iterator] === 'function';

Any smart ideas?

computed properties would be needed for symbol property keys.
@thejameskyle babel currently parses type properties in brackets as ObjectTypeIndexers, which is kind of awkward because that's not really what [someSymbol]: someType is doing...

// for sequelize...

declare opaque type And = symbol;
declare opaque type Or = symbol;

declare interface WhereLogic {
  [And]?: WhereLogic,
  [Or]?: Array<WhereLogic>,
  [field: string]: any,
}

Would be useful for static computed properties too.

Was this page helpful?
0 / 5 - 0 ratings