Minimal example:
type PossiblyEmpty = $Exact<{
a?: number
}>
const p: PossiblyEmpty = {} // this errors. Should it?
https://flowtype.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgAKcAziQJYBGMWAogLY7ZgC8YAJLQB4CGAxhgA8Ab1RgwPAPwAuMADsArvUp4ATqgC+APnR84ckhjA5ZxMlRoMmWVmGEbUQA
Is this by design?
EDIT: inline an example
Yeah, looks like a bug to me. Thanks for the minimal example!
For what it's worth, I am responsible for making this an error (in this commit). In general, unsealed things can't be exact, because other references to them can widen the type in unexpected ways.
In this case, there are no other references, so it doesn't really make sense to consider the object literal to be unsealed. I think the fix here is to _not_ create an unsealed object in this case. var o = {} should be unsealed, but var o: T = {} should not be.
Still getting the error. Is that something that will be fixed?
I would also like to see this fixed. Anytime you are using an options parameter it is helpful to allow {}
@samwgoldman It's still an issue!
Look at https://github.com/facebook/flow/issues/4582#issue-249772183 for a workaround
@lgraziani2712 Why the thumbs down? Does it not work correctly? Please share your experience.
The OP presents an object type with an optional attribute, while that workaround doesn't take in consideration those props. I tested myself with my object full of optionals attributes and it didn't work.
@lgraziani2712 does this not provide your expected results? https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgCiYAvGAN5iphgCGA-AFxgDOGATgJYB2A5gDTUqNYMDAB1OOwDWtdnACu3ACZgoUsHgAetAMYYw2fADoJU6SzqXt+fXmVDRYBAAs83MMry0YPXs84MFzA4ACMAKzx9SyDaA11aD1CCPABbHGxjIQBtRKwAXWY0jKwqAF90XThuNk1mYjJyMrAnbjhNdnl2Fkrq2qh60gowUMYARjBmpzxOqUtaay1bDHsgA
Ok yep, it worked. I did it wrong: I kept the {||} exact pipes (Edit: when I tested before).
Thank you @chrisblossom
type Breakdown = {| [string]: number |};
const breakdown: Breakdown = {};
=>
2: const breakdown: Breakdown = {};
^ Cannot assign object literal to `breakdown` because inexact object literal [1] is incompatible with exact `Breakdown` [2].
References:
2: const breakdown: Breakdown = {};
^ [1]
2: const breakdown: Breakdown = {};
^ [2]
I think the explanation given in https://github.com/facebook/flow/issues/2386#issuecomment-244563036 is the right one. But it's been a while...
Here is a possible workaround until bug is not fixed:
/* @flow */
declare type Criteria = {| option1?: number, option2?: string |};
declare export function init(criteria: Criteria): void;
const test = init({ ...undefined });
Another workaround is $Shape:
/* @flow */
declare type Criteria = $Shape<{option1: number, option2: string}>;
declare export function init(criteria: Criteria): void;
init({}); // ok
init({option1: 3}) // ok
init({option1: 3, rogueProp: 'secret'}) // errors as expected
Another workaround, which to my mind is the cleanest of any I've seen here, is to just pass an explicit undefined. For many purposes the following is equivalent to an empty object:
({foo: undefined}: {|foo?: number, bar?: number|});
Recommend you add the label 'unsealed objects' to this and probably close #2977 as a duplicate of this so that progress/conversation can be tracked in one place.
Another workaround for this issue is to use Object.freeze (playground):
({ x: 3 }: {| x: number |}); // ok
({}: {||}); // error
(Object.freeze({}): {||}); // ok (workaround)
I learned this from the thread at #2977; repeating it here in case it helps others, because this seems to be the canonical thread for this issue.
If you weren't planning to mutate the object, then this workaround is quite clean because it should have no effect at all on the behavior of the code that consumes the object. And in situations where you are planning to mutate the object, I think you typically want the "unsealed object" behavior anyway so this isn't an issue in the first place.
Most helpful comment
@lgraziani2712 does this not provide your expected results? https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgCiYAvGAN5iphgCGA-AFxgDOGATgJYB2A5gDTUqNYMDAB1OOwDWtdnACu3ACZgoUsHgAetAMYYw2fADoJU6SzqXt+fXmVDRYBAAs83MMry0YPXs84MFzA4ACMAKzx9SyDaA11aD1CCPABbHGxjIQBtRKwAXWY0jKwqAF90XThuNk1mYjJyMrAnbjhNdnl2Fkrq2qh60gowUMYARjBmpzxOqUtaay1bDHsgA