New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't assign more specific generic into less specific generic #6884

Open
bsmith-cycorp opened this Issue Sep 13, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@bsmith-cycorp

bsmith-cycorp commented Sep 13, 2018

The following gives an error:

type Superset = Subset1 | Subset2

type Subset1 = {
  prop1: string
}
type Subset2 = {
  prop2: string
}


var moreSpecificArray: Array<Subset1> = [];

var lessSpecificArray: Array<Superset> = moreSpecificArray;
Cannot assign `moreSpecificArray` to `lessSpecificArray` because property `prop1` is missing in `Subset2` [1] but exists in `Subset1` [2] in array element.

Interestingly, changing the following line to this does not give an error:

var lessSpecificArray: Array<Superset> = [].concat(moreSpecificArray);

Try-flow example:
https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgDKArvgE4DOeGYAvEcQEZUYCMYAPg89QEzrZ83Fu3oBvVGDA4ycHKwBcYChjIBLAHYBzVAF9MuAiR4ZedMBKky5vJSvXa96VADcAhmTABbOGTyF8AGM1KDVAgEEyMjcsJUjorAAeYxEAPnMAbQBdAG50d08YPAoKALxg0IiomLjqpJJyFnT6Hz8yirD4mLzXDzAACzdAgGs8ABMAGWLSoJDOutqE5NI8SmpmsGyAOkC4DUC3DAAKVv9Zyq6sAEocoA

@bsmith-cycorp

This comment has been minimized.

Show comment
Hide comment
@bsmith-cycorp

bsmith-cycorp Sep 13, 2018

It's not just a matter of cloning, though, because this doesn't work either:

var lessSpecificArray: Array<Superset> = moreSpecificArray.slice();

bsmith-cycorp commented Sep 13, 2018

It's not just a matter of cloning, though, because this doesn't work either:

var lessSpecificArray: Array<Superset> = moreSpecificArray.slice();
@xanf

This comment has been minimized.

Show comment
Hide comment
@xanf

xanf Sep 13, 2018

@bsmith-cycorp it's absolutely valid behavour. Arrays are invariant by default. To make words simple: since arrays are copied by reference you can doo lessSpecificArray.push, this will validate against Superset type, but will actually add valud to "moreSpecificArray" (since they share same ref).

changing to

var lessSpecificArray: $ReadOnlyArray<Superset> = moreSpecificArray;

makes no errors, since read-only arrays are covariant

xanf commented Sep 13, 2018

@bsmith-cycorp it's absolutely valid behavour. Arrays are invariant by default. To make words simple: since arrays are copied by reference you can doo lessSpecificArray.push, this will validate against Superset type, but will actually add valud to "moreSpecificArray" (since they share same ref).

changing to

var lessSpecificArray: $ReadOnlyArray<Superset> = moreSpecificArray;

makes no errors, since read-only arrays are covariant

@wchargin

This comment has been minimized.

Show comment
Hide comment
@wchargin

wchargin Sep 13, 2018

Contributor

@xanf is entirely correct. Mutable structures are invariant; read-only
structures are covariant.

It's not just a matter of cloning, though, because this doesn't work
either: […]

This is “just” an inference failure. You can solve it by adding a type
annotation
:

/* @flow */
type Superset = Subset1 | Subset2;
type Subset1 = {
  prop1: string
};
type Subset2 = {
  prop2: string
};

var moreSpecificArray: Array<Subset1> = [];
var lessSpecificArray: Array<Superset> = (moreSpecificArray: $ReadOnlyArray<
  Superset
>).slice(); // OK
Contributor

wchargin commented Sep 13, 2018

@xanf is entirely correct. Mutable structures are invariant; read-only
structures are covariant.

It's not just a matter of cloning, though, because this doesn't work
either: […]

This is “just” an inference failure. You can solve it by adding a type
annotation
:

/* @flow */
type Superset = Subset1 | Subset2;
type Subset1 = {
  prop1: string
};
type Subset2 = {
  prop2: string
};

var moreSpecificArray: Array<Subset1> = [];
var lessSpecificArray: Array<Superset> = (moreSpecificArray: $ReadOnlyArray<
  Superset
>).slice(); // OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment