Yangshun Tay
Yangshun Tay

Reputation: 53229

Flow type an array of values with generics

The following code

type Value<T> = {|
  name: string,
  value: T,
|}

const myNumber: Value<number> = { name: 'number', value: 1 };
const myString: Value<string> = { name: 'string', value: 'foo' };

const arr: Array<Value> = [myNumber, myString];

I want to loop through an array of Value objects and get the name value of all my objects, but I'm getting this error:

9: const arr: Array<Value> = [myNumber, myString];
                    ^ Cannot use `Value` [1] without 1 type argument.
References:
1: type Value<T> = {|
             ^ [1]

Any ideas how to fix this without using Value<any>? I'm using flow strict

Flow Playground link

Upvotes: 3

Views: 1441

Answers (3)

Aleksey L.
Aleksey L.

Reputation: 38046

Update In latest version (tested with 0.98.0) flow is able to infer the types properly, so explicit annotation is no longer required. Just go with:

const arr = [myNumber, myString];

Older versions:

In flow you could use Existential Type (*)

An existential type is used as a placeholder to tell Flow to infer the type

const arr: Array<*> = [myNumber, myString];

Playground

Upvotes: 3

Yangshun Tay
Yangshun Tay

Reputation: 53229

I ended up using this as I don't really need to know the type of value.

type Value<T> = {|
  name: string,
  value: T,
|}

const myNumber: Value<number> = { name: 'number', value: 1 };
const myString: Value<string> = { name: 'string', value: 'foo' };

const arr: Array<{name: string}> = [myNumber, myString];

Playground Link

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250406

You need to specify the type argument for the array item type

type Value<T> = {|
  name: string,
  value: T,
|}

const myNumber: Value<number> = { name: 'number', value: 1 };
const myString: Value<string> = { name: 'string', value: 'foo' };

const arr: Array<Value<any>> = [myNumber, myString];

Depending on how strict you want to be you could also use an array with a union type as an item

 const arr: Array<Value<number>|Value<string>> = [myNumber, myString];

Or a tuple type :

const arr: [Value<number>,Value<string>] = [myNumber, myString];

You could also skip the annotation and let the compiler infer the type.

Upvotes: 2

Related Questions