Skip to content
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

Object literal {} incompatible with $Exact<{}> #4582

Closed
jcready opened this issue Aug 11, 2017 · 11 comments
Closed

Object literal {} incompatible with $Exact<{}> #4582

jcready opened this issue Aug 11, 2017 · 11 comments

Comments

@jcready
Copy link
Contributor

jcready commented Aug 11, 2017

type T = $Exact<{}>;
const t: T = {} // flow error

The only work around seems to be to replace $Exact<{}> with { [any]: empty }

type E = { [any]: empty }
const e: E = {}
@mwalkerwells
Copy link
Contributor

Or to simplify without an alias...

const foo: {| bar: 'bar' |} = { bar: 'bar' }

const fooError: {||} = {}
4: const fooError: {||} = {}
                          ^ object literal. Inexact type is incompatible with exact type
4: const fooError: {||} = {}
                   ^ exact type: object type

You're right, this is a surprising behavior.

@mhagmajer
Copy link

+1

skovhus added a commit to skovhus/flow-runtime that referenced this issue Jan 7, 2018
Sometimes `{ [any]: empty }` is used as a workaround instead of `{||}`.

See:
- facebook/flow#2977
- facebook/flow#4582
skovhus added a commit to skovhus/flow-runtime that referenced this issue Jan 7, 2018
Sometimes `{ [any]: empty }` is used as a workaround instead of `{||}`.

See:
- facebook/flow#2977
- facebook/flow#4582
@hon2a
Copy link

hon2a commented Feb 21, 2018

I encountered this when trying to assign an empty object to an exact type defined with an indexer.

type Exact = {|
  [KeyType]: ValueType
|};

Seems like this can be resolved by defining the type as

type PossiblyEmptyExact = Exact | {};

@marcianx
Copy link

marcianx commented Mar 5, 2018

That's not a better workaround since {} is a superclass of all structs. Consequently,

type Foo = {| bar: number |} | {};
const foo: Foo = {bar: "baz"};

is happily accepted by the compiler.

Using a non-exact type would be more type-safe.

@hon2a
Copy link

hon2a commented Mar 5, 2018

@marcianx: Thanks. Seems like I was so happy it worked, I didn't think it through.

@marcianx
Copy link

marcianx commented Mar 5, 2018

@hon2a #5688 has two workarounds. I've used the $Shape one successfully for my workaround.

type Foo = $Shape<{bar: number}>;
const foo1: Foo = {bar: "baz"}; // wrong field type
const foo2: Foo = {qux: "baz"}; // property missing

@mhagmajer
Copy link

Guys, please beware of this issue with shapes: #5884. The currently accept null and undefined.

@hon2a
Copy link

hon2a commented Mar 5, 2018

@marcianx: $Shape allows objects with some of the properties missing.

type T = $Shape<{ a: number, b: number }>;
const partial: T = { a: 1 }; // no errors

In my case $Shape is of no use as I need this for maps (defined with an indexer, e.g. type T = {| [KeyType]: ValueType |}).

@marcianx
Copy link

marcianx commented Mar 5, 2018

@mhagmajer Thanks for pointing this out! The easy workaround for this is to ensure that this is an object via & {}.

type Foo = $Shape<{bar: number}> & {};
const foo: Foo = null; // null is incompatible

@hon2a Thanks for mentioning. I should have explicitly mentioned this -- indeed, this workaround is only for the case where you wish all fields to be optional (which was my case when I ran into this bug).

@AlexanderShushunov
Copy link

I think this code does not work for the same reason.

type T =  {|a?: number|};
const t: T = {};

@vkurchatkin
Copy link
Contributor

Closing in favour of #2977

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants