Can flow distinguish between field declaration using constant and indexer declaration?
const A = 'a';
const B = 'b';
type Foo = {
[A]: string,
[B]: string,
}
7: [A]: string,
^ Cannot use string as a type because string is a value. To get the type of a value usetypeof
.
8: [B]: string,
^ Multiple indexers are not supported.
The { [a]: b }
Notation is reserved for indexed properties. This defines a map from type a
to type b
. What you want to use this notation for is to externalize the keys of specific properties. Is far as I know this is not supported.
Even if it was supported though you would have another problem. A
and B
are values. They may be constant but as far as flow is concerned they are still values so you would have to use typeof
to get their type. What you can do though is convert A
and B
to types where 'a'
and 'b'
literal types.
As long as the property types you want to associate with A
and B
are the same you can then create a union of them and use that as the key type
You can do this right now.
If/once https://github.com/facebook/flow/pull/4175 gets merged, you wouldn't need to write the types of A
and B
explicitly, cause it wouldn't be just string
anymore.
The multiple indexer's bit would still be unsupported though. I'll tag this as a feature request for that.
Thanks @chisui and @mrkev. I'm aware about the union workaround, but it won't work if fields have different value types. I'm not trying to define indexer/multiple indexers, but define fields using consts as their names (works in typescript and thought it would be nice if flow had something similar)
const A = 'a';
const B = 'b';
const C = 'c';
type Foo = {
[A]: number,
[B]: string,
[C]: boolean
}
Yup, that's what I meant by the multiple indexer bit; flow supports only one. I agree it could come in handy.
You can have a union of the value types like you can have a union of index types. Unfortunately that would allow all values of any value types to be assigned to a field of any index type since there effectively exist only one index type and one value type.
I just pondered how would multiple indexers work. What should happen if index types intersect?
type T = {
[ A | B ]: V,
[ B | C ]: W,
}
The type of T[B]
would be V | W
. That could get complex fast if the index types are non trivial or if there are more indexers.
The first one to match could be taken. That's kind of how the definition for Object
works, with that last honeypot case: https://github.com/facebook/flow/blob/v0.75/lib/core.js#L69
There could also be static analysis in place to ensure they don't intersect, and throw an error (or a warning) if they do ¯\_(ツ)_/¯
Again people, no one tried to define multiple indexer types, but "computed properties" if you wish. In this scenario I'd like flow to treat const value as a key (not as a type). I understand that this is not supported currently, but what I would expect is the following transformation:
const A = 'a';
const B = 'b';
const C = 'c';
type Foo = { type Foo = {
[A]: number, a: number,
[B]: string, => b: string,
[C]: boolean c: boolean
} }
I'm hitting this because I expected it to work so I could define immutable records and only define the key once.
export const MY_KEY = 'my-key';
export type MyRecordProps = {
[MY_KEY]: ?string
};
export const MyRecord: RecordFactory<MyRecordProps> = Record({
[MY_KEY]: null
});
Then later...
record.get(MY_KEY);
Most helpful comment
Again people, no one tried to define multiple indexer types, but "computed properties" if you wish. In this scenario I'd like flow to treat const value as a key (not as a type). I understand that this is not supported currently, but what I would expect is the following transformation:
This is how it works in typescript