Flow: Flow doesn't like Symbols as object keys

Created on 24 Jan 2017  路  25Comments  路  Source: facebook/flow

try flow

const x = {[Symbol.for('foo')]: 42};

yields

1: const x = {[Symbol.for('foo')]: 42};
             ^ object literal. Computed property cannot be assigned with
1: const x = {[Symbol.for('foo')]: 42};
               ^ Symbol
object model feature request incompleteness

Most helpful comment

@nodkz The proper issue is FlowType's lack of support for Symbols. The issue of computed types is occasionally a related issue. Additionally my example reproduces the same issue as the OPs, regardless of whether or not you can achieve the same error with strings. smh.

Nonetheless, I'll monitor the issue to see if you can help the OP because if you can, then my issue will likely be solved as well.

All 25 comments

6 days later @zyklus ... just ran into exactly same issue.

bump

I have the same issue with boolean keys:

"Computed property cannot be assigned with boolean"

any news on this? just ran into it today as well.

Symbols are completely unsupported at the moment.

:( can not even use flow at all if the file has symbols. kills my type coverage !

This incompleteness forces to relax asyncIterator checks to any in graphql-js.
Now if your are using Flow 0.54 in your app and try to upgrade to the latest graphql-js you will get bunch of errors.

With 0.53.1 was no errors. So regression appeared in 0.54
https://github.com/graphql/graphql-js/pull/1023

PS. If somebody in its isomorphic app upgrade till 0.54 and made non-backward compatible changes with React component annotations, you may downgrade flow till 0.53.1. Then graphql-js and new react-annotations will work without errors.

If nothing else provide a ignore_symbols_as_keys=true config option until Flowtype has things sorted with Symbol usage. I also use Symbol.for as well as other Symbol predefined types and this is an issue. ignore_computed_key_access=true is also highly desirable.

@nyteshade i did not find such options in flow 0.54 docs

[options]
ignore_symbols_as_keys=true
ignore_computed_key_access=true

tested them and got such errors in terminal

$ "/Users/nod/www/_npm/graphql-js/node_modules/.bin/flow"
.flowconfig:14 Unsupported option specified! (ignore_computed_key_access)
.flowconfig:13 Unsupported option specified! (ignore_symbols_as_keys)

@nodkz I know! I want them to implement these!

@nyteshade I think there is no such need in these options. For such cases exists any or // $FlowFixType.

If we add such options in libs, so we force our packages' consumers to set the same options in their apps. The easy way to use any, cause no need in additional setting with same Flow checks behavior.

So Symbols should work or not, no intermediate state 馃槈

@nodkz Then they should happily make them work, since Symbols are clearly a part of ES6+. Computed access keys like [Symbol.for("someString")]: value work nearly everywhere ES6 is supported but I have had to mark up my code with a suppress_comment for each line because flowtype doesn't allow us a way (that I know of) to disable errors for computed types.

@nyteshade for me current solution is to mark "computed type" as :any:

const a: AsyncIterator<mixed> = (computedType: any);

// or

function processAsyncIterator(ai: AsyncIterator<mixed>) {
  // ...
}
processAsyncIterator((computedType: any));

The same suggestion from calebmer.

UPD: And in the same way ( ...: any) @mroch resolved graphql-js errors with Flow 0.54

A more complete example of what doesn't work for me then. This is about as concise as I can make this quickly. This example is contrived but exemplifies the issues.

// @flow
export class BaseObject {
  constructor() {
    this[Symbol.for('backing-store')] = {}
  }

  get model(): Object { 
    return this[Symbol.for('backing-store')];
  }

  get [Symbol.toStringTag](): string {
    return this.constructor.name;
  }

  static get [Symbol.toStringTag](): string {
    return this.name;
  } 
}

screen shot 2017-09-05 at 10 14 31 pm

@nyteshade your errors are not referenced to this issue.
I replaced Symbols on 'abc' strings and got the same errors.

assignment of computed property/element
computed property keys not supported

Please find a proper issue with your problem. I don't want to disturb current 9 participants in this issue anymore. Thanks.

@nodkz The proper issue is FlowType's lack of support for Symbols. The issue of computed types is occasionally a related issue. Additionally my example reproduces the same issue as the OPs, regardless of whether or not you can achieve the same error with strings. smh.

Nonetheless, I'll monitor the issue to see if you can help the OP because if you can, then my issue will likely be solved as well.

Ran into this today when using Flow with React Redux and symbol action types.

@nyteshade I think there is no such need in these options. For such cases exists any or // $FlowFixType

For future readers: It's // $FlowFixMe.

I wrote up a workaround for implementing [Symbol.iterator] with proper typchecking. I think that the same workaround should extend to [Symbol.asyncIterator].

https://stackoverflow.com/a/48528104/103017

The workaround is to put a // $FlowFixMe annotation on the computed property name as @nodkz and @happylynx suggested, and to define an equivalent property using the special name that Flow uses internally (@@iterator or @@asyncIterator) so that Flow treats the type is an iterable / async iterable. The @@iterator / @@asyncIterator definition should be in a Flow comment, because those special names are not valid property names outside of Flow, and there is no need for them to exist at runtime anyway.

Here is an example from my post:

export class A {
  // $FlowFixMe
  [Symbol.iterator](): Iterator<string> {
    return {
      next() {
        return {
          done: true
        }
      }
    }
  }

  /*::
  @@iterator(): Iterator<string> {
    // $FlowFixMe
    return this[Symbol.iterator]()
  }
  */
}

Feel sad about it. I am currently implementing operator overloading in flow syntax. Without supporting computed symbol keys, I cannot apply the magic operator under flow.

I'm not sure, if I should open new issue for that, but I found a relative issue:
https://flow.org/try/#0PTAEAEDMBsHsHcBQBjWA7AzgF1AQ1ALygDeiooWsAylgE4CWaA5gFygAUAlIQHygDkARn4AaRAF8A3IhTpsoAEaESZUAG1cAXTaCATAGYxUmakyxoAUwB0cJu34KN20YqedpQA

// @flow
const a = {
  toString: () => '1',
};

const b = {
  [a]: 123,
};

console.log('b[a]:', b[a]);

This code works perfectly due to toString operator, but flow throws computed key access error.

@vaukalak if flow worked like that then it would make the string constraint useless since pretty much everything has a toString() method in its prototype.

@jcready I don't think that's a bad solution, cause it's totally valid JS.
Another possible solution, would be to consider to allow mapping for every user defined type that has toString. Flow has syntax { [SomeType]: number }, for that reason I'm unsure why not to use it. As here: https://flow.org/try/#0PTAEAEDMBsHsHcBQAXAngBwKagIKgLygDeoysAysgE4CWAdgOYBcoAFAJQEB8oAztfQYAaUJFiwWdAK4BbAEaYqoAL4BuRIgDGsOv1ABDFnkJFEoUhQGMWHbqADk+gPoBGe0LOjxLFx7Ua0LFwAWX10AmJQAG0cAF1JWQUlf0RoTGQDUPQjLPUtHT19LIAmFhIY+NBpeUUVCNNzKP1Kl2KAZj887V1YNIA6OAZWRxKm+PdMsOKx9nUgA

Just my thoughts.

@mroch What is the latest with this?

@nodkz Symbol properties are needed to write some library definitions properly, there's just no way around it, any isn't a viable solution. For example here are some of the TS type defs for sequelize; Op.any, Op.gte, etc. are symbols. Totally impossible to typecheck code that uses them in Flow right now, but it would be of great benefit to users if we could use these symbols in the type defs so that users get the correct type checking.

/**
 * Operators that can be used in WhereOptions
 *
 * See https://sequelize.org/master/en/v3/docs/querying/#operators
 */
export interface WhereOperators {
  /**
   * Example: `[Op.any]: [2,3]` becomes `ANY ARRAY[2, 3]::INTEGER`
   *
   * _PG only_
   */
  [Op.any]?: (string | number | Literal)[] | Literal;

  /** Example: `[Op.gte]: 6,` becomes `>= 6` */
  [Op.gte]?: number | string | Date | Literal;

  /** Example: `[Op.lt]: 10,` becomes `< 10` */
  [Op.lt]?: number | string | Date | Literal;

  /** Example: `[Op.lte]: 10,` becomes `<= 10` */
  [Op.lte]?: number | string | Date | Literal;

  /** Example: `[Op.ne]: 20,` becomes `!= 20` */
  [Op.ne]?: string | number | Literal | WhereOperators;

  /** Example: `[Op.not]: true,` becomes `IS NOT TRUE` */
  [Op.not]?: boolean | string | number |  Literal | WhereOperators;
Was this page helpful?
0 / 5 - 0 ratings