Flow: Computed property cannot be assigned with class instance

Created on 28 Jan 2017  路  3Comments  路  Source: facebook/flow

For a configuration system, I'd like a type that can only be used as object keys not as values, so I created a class with a toString() method like so:

const myKeys: {[key: string]: MyKey} = {};

class MyKey {
  name: string;
  constructor(name: string) {
    this.name = name;
    myKeys[name] = this;
  }
  toString(): string {
    return this.name;
  }
}

type MyMap = {[key: MyKey]: string};

const m1: MyMap = {};
const k = new MyKey('foo');
m1[k] = 'foo';

const m2: MyMap = {[k]: 'foo'};

While Flow is happy with regular object assignment, it does not work when used as a computed property:

21: const m2: MyMap = {[k]: 'foo'};
                      ^ object literal. Computed property cannot be assigned with
21: const m2: MyMap = {[k]: 'foo'};
                        ^ MyKey

flowtype.org/try example

Most helpful comment

I'm looking to leverage Flow's type checking rather than require library consumers to switch it off each time they use a computed property (a frequent occurrence with this library.)

I'd hoped I might be able to work around this using opaque types, but sadly it looks not, even if I declare the opaque type with a string supertype. (I'm using declare opaque type here to simulate usage from another file.)

/* @flow */

const myKeys: {[key: string]: MyKey} = {};

class MyKey {
  name: string;
  constructor(name: string) {
    this.name = name;
    myKeys[name] = this;
  }
  toString(): string {
    return this.name;
  }
}

declare opaque type MyKeyOpaque: string;
type MyMap = {[key: MyKeyOpaque]: string};

function myKeyOpaque(name: string): MyKeyOpaque {
    return (new MyKey(name): any);
}

const m1: MyMap = {};
const k = myKeyOpaque('foo');
m1[k] = 'foo';

const m2: MyMap = { [k]: 'foo' };

Errors (v0.66.0):

27: const m2: MyMap = { [k]: 'foo' };
                         ^ Cannot assign computed property using `MyKeyOpaque` [1].
References:
19: function myKeyOpaque(name: string): MyKeyOpaque {
                                        ^ [1]

All 3 comments

Try (objectName:any)[variableName].

I'm using flow v0.51.1, this works well.

const myKeys: {[key: string]: MyKey} = {};

class MyKey {
  name: string;

  constructor(name: string) {
    this.name = name;
    (myKeys:any)[name] = this;
  }
  toString(): string {
    return this.name;
  }
}

type MyMap = {[key: MyKey]: string};

const m1: MyMap = {};
const k = new MyKey('foo');
(m1:any)[k] = 'foo';

const m2: MyMap = {[(k:any)]: 'foo'};

console.log(myKeys);
//=> { foo: MyKey { name: 'foo' } }

I'm looking to leverage Flow's type checking rather than require library consumers to switch it off each time they use a computed property (a frequent occurrence with this library.)

I'd hoped I might be able to work around this using opaque types, but sadly it looks not, even if I declare the opaque type with a string supertype. (I'm using declare opaque type here to simulate usage from another file.)

/* @flow */

const myKeys: {[key: string]: MyKey} = {};

class MyKey {
  name: string;
  constructor(name: string) {
    this.name = name;
    myKeys[name] = this;
  }
  toString(): string {
    return this.name;
  }
}

declare opaque type MyKeyOpaque: string;
type MyMap = {[key: MyKeyOpaque]: string};

function myKeyOpaque(name: string): MyKeyOpaque {
    return (new MyKey(name): any);
}

const m1: MyMap = {};
const k = myKeyOpaque('foo');
m1[k] = 'foo';

const m2: MyMap = { [k]: 'foo' };

Errors (v0.66.0):

27: const m2: MyMap = { [k]: 'foo' };
                         ^ Cannot assign computed property using `MyKeyOpaque` [1].
References:
19: function myKeyOpaque(name: string): MyKeyOpaque {
                                        ^ [1]

This also would be extremely helpful when using redux

const action = { type: 'foo', toString() { return this.type; } }

const reducerHandlers = {
  [action]: () => {} // 馃憥 Cannot assign computed property using object literal
}
Was this page helpful?
0 / 5 - 0 ratings