Flow: Is "Object" an implicit "any"?

Created on 27 Aug 2017  路  13Comments  路  Source: facebook/flow

It surprises me that this doesn't cause any errors. Code:

// With or without "Object" type annotation - no difference
const o: Object = {};

// Test 1 (no error)
o.iDontEvenExist();

// Test 2 (no error)
// This is inconsistent even without knowing anything about the object
const n: number = o.number;
const s: string = o.number;
const b: boolean = o.number;

// Finally - at least THIS is an error
const f: string = o;


Flow try link


I think this is too weak. If people don't want to be specific they should say so in their code and use "any".

feature request

Most helpful comment

@TrySound As you can see in jcready's answer, of course there is any involved. You even replied _twice_ without contributing anything useful.

It's not weak.

Please have a look at my initial comment.

All 13 comments

any is not only object. Object is any object. It's quite useful in opposite to {} to pass random object which does not have type annotations.

It's not weak. It allows to specify that I need an object here, not string or number.

It has to with the Object class including this indexer:

[key:any]: any

The same thing is on the Array<T> class as well:

[key: number]: T;
// no errors
const obj = {}
const arr = []
const a: string = obj.foo.bar
const b: string = arr[42].baz

@TrySound As you can see in jcready's answer, of course there is any involved. You even replied _twice_ without contributing anything useful.

It's not weak.

Please have a look at my initial comment.

You can force individual objects to no allow this by annotating the object with your own indexer.

type mixedObj = { [key:any]: mixed }
const o: mixedObj = {}

From there all of your original expected errors should trigger. I have a feeling that the reason Object and Array<T> have the any indexers is to make adoption easier, but I agree that it's not desirable in all cases.

@jcready Thanks, but my point is that this is unexpected. After a reasonably long time with Flow I feel I can work with the many limitations (many of them not anybody's fault, that's just what is possible), yet it caught even me off guard. I think this should not just pass the way it does. You can find presentations touting how Flow is more strict than its competitor - I don't think the above example, and it even is something common and not something exotic, is inconsistent with that narrative.

Basically, with this behavior the Flow type Object is just one step removed from any (oh hey, there _is_ an object), since I can access _whatever_ and Flow just shrugs and says "yeah, sure, whatever you want man".

Oh, I'm totally with you. I just doubt the flow team would ever accept a PR where you flip those indexers from any to mixed. Maybe there could be a possibility for flow to add a new pragma // @flow-strict which would just interpret all any types as mixed or something.

Indeed, Object means AnyObject.

Can you describe the case where you needed to use the Object type but where this was unexpected behavior?

In my own code I rarely use Object at all. Either I use an object as a dictionary-like thing ([key: string]: Whatever) or I know the shape of the object and use a specific object type ({a: number, b: string}). Pretty much the only time I use Object is if I need to pass through typed code a complex configuration object bound for an untyped library.

If there's a case where you have an Object and need to treat it more strictly, I bet we can find a good way to do that in Flow.

He's not talking about using the Object type annotation (specifically). The issue happens without using annotations on the object. See my first comment. And unless you specify a exact object type or define your own indexer for an object type, the resulting object will still return any for any key you access on it which isn't explicitly typed.

Ah, thanks for the clarification and sorry I didn't read the intent of this carefully enough.

So this seems to happen differently depending on the object literal that's used.

For example, if the object literal has some properties, then accessing another one that isn't present does give an error:

let obj = { a: "a", b: "b" };
obj.c; // property c not found

If I read the initial comment as being specifically about the type inferred for an empty object, I'm curious what people would suggest as a better option. It could be inferred as {| |} (object with absolutely no properties), but that's a pretty much useless type and rarely what real-world code means.

I would guess that most real-world code using let obj = {} is right about to mutate and add some properties onto the empty object, so Flow assumes it should just guess Object because things are about to be added dynamically with unknown keys and types.

But, like I said, curious to hear what people think the inferred type _ought_ to be.

This is expected behavior, and a reason why @flow strict includes a lint rule against it.

Object essentially means it can be any object, and this includes object with any keys and keys of any type. If possible, it's good to avoid it.

I am rather split about inferring { [string]: any } for const o = {}-- it's a side-effect of having it be an unsealed object you can assign to. I wonder if it's possible to have it be unsealed for writing, so people can do:

const o = {}
o.foo = 'bar'

but not for reading, and rely on the inferred shape of the object for that.

EDIT: Or at the very least mark this as an error on @flow strict.

To follow up here and answer your original question, Object is now an alias to any. Before it was more or less { [key: string]: any }. I've also put together some codemods to rename Object accordingly, if you'd like to use them: https://github.com/facebook/flow/issues/7291

Also, it seems like this ticket is conflating a few different things. Specifically around what Object means, and also unsealed objects and their behavior. I'm going to close this in favor of: #7291 and #7424

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cubika picture cubika  路  3Comments

ctrlplusb picture ctrlplusb  路  3Comments

tp picture tp  路  3Comments

philikon picture philikon  路  3Comments

funtaps picture funtaps  路  3Comments