Flow: Object types intersection within generics within object types

Created on 27 Jun 2017  路  2Comments  路  Source: facebook/flow

Trying to intersect object types within generics inside object types.

type C = {
  beers: Array<{
    brand: string
  }>
}

type D = {
  beers: Array<{
    size: number
  }>
}

type CD = C & D;

var cd: CD = {beers : [{brand: 'Rothhaus', size: 0.5}]}

The variable cd does not fit the type CD. Is this the expected behavior?

Althought it works with this example.

type beerWithBrand = {
    brand: string
}

type beerWithSize = {
    size: number
}

type beerStock = {
    beers: Array<beerWithBrand & beerWithSize> 
}

var stock : beerStock = {beers : [{brand: 'Rothhaus', size: 0.5}]} 

Most helpful comment

Arrays are invariant because they're mutable in JavaScript.

This means that A <: B does _not_ imply that Array<A> <: Array<B> (covariance), nor does it imply that Array<B> <: Array<A> (contravariance). For example, consider:

type A = {brand: string, size: number};
type B = {brand: string};

It's clear that A <: B (subtype). If it were true that Array<A> <: Array<B> (covariance), then this is legal:

const array: Array<A> = [{brand: 'red stripe', size: 99}];
const bArray: Array<B> = array; // because Array<A> <: Array<B>
bArray.push({brand: 'sizeless'}); // because this is an Array<B>
(array[1]: A); // This passes Flow, but it's actually not an A

Similarly, arrays cannot be contravariant because if A <: B implies Array<B> <: Array<A>, then this is legal:

const array: Array<B> = [{brand: 'red stripe'}];
const aArray: Array<A> = array; // because Array<B> <: Array<A>
(aArray[0]: A); // This passes Flow, but it's not actually an A

If you want covariant arrays, they must be read-only. You can declare this type with $ReadOnlyArray<T>

All 2 comments

Arrays are invariant because they're mutable in JavaScript.

This means that A <: B does _not_ imply that Array<A> <: Array<B> (covariance), nor does it imply that Array<B> <: Array<A> (contravariance). For example, consider:

type A = {brand: string, size: number};
type B = {brand: string};

It's clear that A <: B (subtype). If it were true that Array<A> <: Array<B> (covariance), then this is legal:

const array: Array<A> = [{brand: 'red stripe', size: 99}];
const bArray: Array<B> = array; // because Array<A> <: Array<B>
bArray.push({brand: 'sizeless'}); // because this is an Array<B>
(array[1]: A); // This passes Flow, but it's actually not an A

Similarly, arrays cannot be contravariant because if A <: B implies Array<B> <: Array<A>, then this is legal:

const array: Array<B> = [{brand: 'red stripe'}];
const aArray: Array<A> = array; // because Array<B> <: Array<A>
(aArray[0]: A); // This passes Flow, but it's not actually an A

If you want covariant arrays, they must be read-only. You can declare this type with $ReadOnlyArray<T>

@danwang, do you have an idea how I could extend arrays from an imported, auto-generated type? Please check: https://stackoverflow.com/questions/44786085/how-to-use-flow-intersection-types-on-arrays-to-extend-an-auto-generated-type

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mmollaverdi picture mmollaverdi  路  3Comments

cubika picture cubika  路  3Comments

l2silver picture l2silver  路  3Comments

funtaps picture funtaps  路  3Comments

john-gold picture john-gold  路  3Comments