This may have been reported in other forms but fairly hard to search specifically - didn't find anything matching on first search.
type ONE = {
value: boolean
}
type TWO = {
value: false
}
const one: ONE = {
value: true
}
const two: TWO = {
...one,
value: false
}
Should work since we can guarantee in this case the two.value is false. This makes it very hard to incrementally build types which will eventually be a union of possible types.
Ofc it should also understand in the opposite case where one is spread AFTER value: false as then the error it presents should, in fact, be present since the resulting type would be { value: boolean } (or { value: true } if its a literal type)
16: const two: TWO = {
^ Cannot assign object literal to `two` because boolean [1] is incompatible with boolean literal `false` [2] in property `value`.
References:
4: value: boolean
^ [1]
8: value: false
^ [2]
Note that similarly this comes up in any case you try to spread values in to modify other values in this way. It becomes quite literally impossible to incrementally build any objects without creating tons of variations of objects without any dynamic building of those objects without iterating every single object every single time and removing those values and then spreading after that with something like _.omit() or by directly re-applying all the values that made up the first type into the second.
type ONE = {
value: true
}
type TWO = {
value: false
}
const one: ONE = {
value: true
}
const two: TWO = {
...one,
value: false
}
16: const two: TWO = {
^ Cannot assign object literal to `two` because boolean literal `true` [1] is incompatible with boolean literal `false` [2] in property `value`.
References:
4: value: true
^ [1]
8: value: false
^ [2]
The only solution I know of that is not ideal clearly as it pretty much just destroys type safety is doing
const two: TWO = {
...(one: any),
value: false
}
You can just look up label for similar issues
This is my current main project
@jbrown215 excellent! glad y'all got it under control!!
type SomeType = {
prop: number | null,
};
function someFunc(
customFields: $Shape<SomeType>
): SomeType {
const result: SomeType = {
prop: null,
...customFields,
};
return result;
}
What's slightly different with the above use case is that we first specify default values and _then_ spread what comes in a function.
type SomeType = {
prop: number | null,
};
function someFunc(
customFields: $Shape<SomeType>
): SomeType {
const defaults = { prop: null };
return {
...defaults,
...customFields,
};
}
$Shape has its own set of problems too. It doesn't actually do what it says it does in the documentation, which makes spreading it kind of funky. I'm still not sure what I'm going to do about it with my spread work.
@jbrown215 make Partial or property modifiers :p
:P Well that would certainly be nice, but I also want to make sure existing code still mostly works
@jbrown215 I mean $Shape would still be the same, just add new type
To me it seems as if it is currently always concatenating the types. I suppose the desired outcome is something along the lines of concatenating all optional types and overriding the moment there is a non optional type ?
type ONE = {
value: boolean,
};
type TWO = {
value: false,
};
const one: ONE = {
value: true,
};
const two = {
...one,
...({ value: false }: TWO),
};
gives me {| value: boolean | false |} for two
another more elaborate test case:
https://flow.org/try/#0MYewdgzgLgBAgjAvDA3gKBjA1gUwJ4BcMAjGgL5pqiSwBCSqGMAdK3ADRO6EwDkAhjGgAnAJZgA5r3KUA9LKFQxkmAB8YYAK4BbAEY5haWs27NgAC37C4UABQAGAJRGT+GAoBMlatBgAFKxwwWGR0TCg8AAccImJOTG0cKHMQABNbcUjNKCIRcQlHXKV8xgBIYSTNYTAYTOymCgoqcF8AYXNRABtUhjCWVgCK4PiYCOiiXgAJfk7OkF4RxOS0jLAsnI0dfWFCzb0DRkxyyuratfrMMhgZNHau1OYllPTiZzvux6Tn2148yV5nLcOh8xjgzJZrHYnED7sxQe4YF5KEA
I also ran into into problems with $Shape and spreads when trying to upgrade to Flow 0.106.2. Is this the same issue, or should I file a new one?
The below seems to be a regression(?) introduced in 0.106.0. However when all types are changed to exact in this example, the same error _also_ occurs in older versions. Perhaps I'm misusing $Shape?
/* @flow */
type Foo = { x: string };
type Bar = $Shape<Foo>; // doesn't work (this is the one I want to use)
//type Bar = $ObjMap<Foo, <T>(T) => T | void>; // doesn't work (attempted workaround)
//type Bar = { x?: string }; // works (but doesn't allow me to define in terms of Foo)
type Merged = { ...Bar, y: number };
// Error: Cannot assign object literal to `m` because property `x` is missing in object literal [1] but exists in `Merged` [2].
const m: Merged = { y: 1 };
@jtbandes, try $Rest<Foo, {}>
Thanks, that works! But why should $Shape be different?
$Shape has a bunch of issues. I hope that we will get rid of it entirely in favor of something better
@jbrown215 has landed his spread improvements, and the original example no longer errors in master.
Nice, my example in https://github.com/facebook/flow/issues/7767#issuecomment-517693696 works also on master! Thanks!
Most helpful comment
This is my current main project