facebook / flow

Adds static typing to JavaScript to improve developer productivity and code quality.
https://flow.org/
MIT License
22.09k stars 1.86k forks source link

Admits object literals with incompatible types to map when using computed properties #1971

Open ned opened 8 years ago

ned commented 8 years ago

When using a map type, such as {[key: string]: number}, with an object literal that uses computed properties, Flow seems to be failing to detect that the types of the key or value of the object are not compatible with the map type.

// @flow

type Map = {[key: string]: number}

/* Neither the key or value types are correct, but Flow
 * still admits them.
 */
const a: Map = {[0]: "hello"};

/* Same problem.
 *
 * This is a common scenario in Redux projects, where
 * the spread operator is used to make a copy.
 *     return {...old, [id]: value}
 */
function f(): Map {
    return {[0]: "hello"};
}

/* This version DOES throw an error, for both
 * the key and value, as desired
 */
const b: Map = {};
b[0] = "hello";

/* This also correctly throws an error for the value */
const c: Map = {["0"]: "hello"};

/* As does this */
const d: Map = {"0": "hello"};

/* But this fails to throw an error */
const e: Map = {["" + "0"]: "hello"};
echojc commented 8 years ago

I've encountered a similar issue where an explicit type annotation on the value used as the key of a computed property also stops Flow from reporting incompatible values in the map.

/* @flow */

const key = 'key1';
const annotatedKey: string = 'key2';

const map: { [key: string]: string } = {
  [key]: 1,
  [annotatedKey]: 2
};

map[key] = 3;
map[annotatedKey] = 4;

Flow only reports errors for cases 1, 3 and 4, but all four cases should fail.

7:   [key]: 1,
            ^ number. This type is incompatible with
6: const map: { [key: string]: string } = {
                               ^ string
11: map[key] = 3;
               ^ number. This type is incompatible with
6: const map: { [key: string]: string } = {
                               ^ string
12: map[annotatedKey] = 4;
                        ^ number. This type is incompatible with
6: const map: { [key: string]: string } = {
                               ^ string
gkz commented 10 months ago

Fixed for number keys in 80ca16f77ba81a3475dd1f7a9f4d9d9e3d71bca8 (all but example e in initial example).