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

For var in object: Var is implicitly any without error #4518

Closed
M-Pixel opened this issue Aug 28, 2015 · 14 comments
Closed

For var in object: Var is implicitly any without error #4518

M-Pixel opened this issue Aug 28, 2015 · 14 comments
Labels
Breaking Change Would introduce errors in existing code Committed The team has roadmapped this issue In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@M-Pixel
Copy link

M-Pixel commented Aug 28, 2015

In the following statement,

for (let subscription in this._subscriptions) {
    // Do something with subscription
}

The variable subscription is considered type any. Although I'm compiling with noImplicitAny as true, no error is given. Based on the for spec, it seems as if subscription should implicitly be considered string.

Because of this, it's possible to compile with typo functions that will cause errors at runtime.

@DanielRosenwasser DanielRosenwasser changed the title For var of object: Var is implicitly any without error For var in object: Var is implicitly any without error Aug 28, 2015
@DanielRosenwasser
Copy link
Member

#3500 is partially related.

@M-Pixel
Copy link
Author

M-Pixel commented Aug 28, 2015

It is! From that thread, it sounds like keys can be number | sybmol | string, but specifying this would still allow more intelligent autocomplete and warnings.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 28, 2015

for the record, this will be a breaking change.

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Aug 28, 2015
@drake7707
Copy link

This might be beside the point but shouldn't the correct code in this case be :

for (let subscription OF this._subscriptions) {
    // Do something with subscription
}

with 'of' instead of 'in'?

@M-Pixel
Copy link
Author

M-Pixel commented Aug 31, 2015

No, because of is for iterating arrays, while in is for iterating objects (in most cases, objects being utilized as maps).

In the case of of, the var is implicitly the type specified in the Array type parameter. I do believe that works correctly already.

@JirkaDellOro
Copy link

Yes, #3500 is related but unfortunately it has been closed! I'd appreciate discussing this further. There are some aspects in the last post that was written almost two months ago, that may be worth thinking about. This thread #4518 is yet another point for allowing the explicit any...

@jeffreymorlan
Copy link
Contributor

My understanding of ES6 is that for/in iteration should only ever yield strings, not number or symbol. Numbers are returned as strings, and symbols are omitted entirely. So there is no need to use a union type.

For/in iteration is defined in terms of the [[Enumerate]] internal method, which in turn is defined (for non-Proxy objects) in 9.1.11:

When the [[Enumerate]] internal method of O is called the following steps are taken: Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of enumerable properties of O. [emphasis mine]

As far as I can tell, the only way to get for/in to return non-strings is to be intentionally evil by creating a Proxy with an Enumerate handler that returns non-string values.

As an experiment I tried changing tsc to make for/in variables stringType instead of anyType, and checked a large codebase - two errors were added, both of which indicated actual bugs (string compared to number with ===).

@vladima
Copy link
Contributor

vladima commented Dec 28, 2015

that is the good point. informal definition here only returns keys of type string. @bterlson can you please confirm that our reading of the spec is correct and the for/in can only yield strings?

@JirkaDellOro
Copy link

Whatever the outcome of this, please make sure that the explicit annotation is allowed in those loops and the catch statement for consistency! Even if it stays with 'any'...

@bterlson
Copy link
Member

For-in can only enumerate strings. The current spec allows proxy enumerate to return non-string keys, but this is changed per consensus though not yet in the spec (see: tc39/ecma262#160).

@DanielRosenwasser DanielRosenwasser added the Breaking Change Would introduce errors in existing code label Dec 31, 2015
@ahejlsberg
Copy link
Member

An implementation of this suggestion is now available in #6379 (this replaces #6302).

@ahejlsberg ahejlsberg added the Committed The team has roadmapped this issue label Jan 8, 2016
@JirkaDellOro
Copy link

Sounds very good. Is the explicit annotation as string allowed now?

@ahejlsberg
Copy link
Member

@JirkaDellOro Explicit type annotations still aren't supported. The type of a variable declared in for-in is always string, and the type of a variable declared in for-of is always the element type. Allowing annotations would leave the impression that other types are possible which isn't really the case (the only types you could write would be ones that are less specific, which isn't really useful).

@JirkaDellOro
Copy link

@ahejlsberg Since I'm using TypeScript to teach programming to beginners, having this inconsistency in the language is very irritating. We use explicit type annotations to get them thinking about data types, and since they need the competence when switching to other languages. All is well, just in those loops and in the catch statement, we have exceptions which are not explainable. It doesn't make sense to strictly disallow the annotation of the type that's used implicitly anyway.

I'd very much appreciate if we could annotate the type explicitly for the sake of consistency of the syntax, and it would be great to only have string allowed in the for..in loop. Just like it's already implemented for associative arrays:

interface ITest {
[key: boolean]: string;
}

TypeScript tells me: "An index signature parameter type must be 'string' or 'number'." PERFECT! I got the syntax right and consistent, but there is a logical mistake that I can easily fix. We have a limitation of possible types. There already was a lenghty and detailled discussion on this topic here: #3500

PS: TypeScript is great!

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Breaking Change Would introduce errors in existing code Committed The team has roadmapped this issue In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

9 participants