-
Notifications
You must be signed in to change notification settings - Fork 12.8k
for .. in type is wrong for objects as const #49621
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
Comments
Duplicate of #44706. |
This issue is different, as this one is restricted only to objects |
That makes no difference. Objects are not sealed. const myConstObj = {
a: "test1",
b: "test2"
} as const;
type Data = {
a: "test1";
b: "test2";
c?: number;
}
function foo(data: Data) { data.c = 123; }
foo(myConstObj);
for (const key in myConstObj) {
// Will print out: a, b, c
console.log(key);
} The only case where this would work safely is if the object is used right after it's been declared, like in your example. But that's such a narrow corner case that I doubt the team will support it. |
The feature needed to make this OK is exact types. const myConstObjTmp = {
a: "test1",
b: "test2"
} as const;
const gotcha = { a: "test1", b: "test2", c: "test3" } as const;
const myConstObj: typeof myConstObjTmp = gotcha; |
I understand your points, indeed there are many valid scenarios where that type I suggested would not be correct 🤔 I mean, this doesn't work, but something like this I think would be very useful: const myConstObj = {
a: "test1",
b: "test2"
} as const;
for (const objKey (as keyof typeof myConstObj) in myConstObj) {
myConstObj[objKey]
} |
I'm now also thinking, that you're right that the type I suggested is not correct in many scenarios, however, I still think there might be a narrower type. So, taking @MartinJohns's example, why can't the inferred type be |
Because the compiler doesn't know there's a property |
Mmh, interesting, thank you everybody for all your explanations 😊 I think this issue can be closed 😊 |
Alternative workaround const myConstObj = {
a: "test1",
b: "test2"
} as const;
for (const objKey of Object.keys(myConstObj) as (keyof typeof myConstObj)[]) {
myConstObj[objKey]
} |
function getObjectKeysUnsafe<T extends object>(value: T): (keyof T)[] { return Object.keys(value) as (keyof T)[]; }
for (const objKey of getObjectKeysUnsafe(myConstObj)) {
myConstObj[objKey]
} |
Nice, thanks 😊 |
I found that using a |
Here's a gist for those cases where you're sure the object is not modified at runtime: https://gist.github.com/JosXa/a76b4e4cde1ef8ac7092a1dff670aa68 |
Bug Report
When declaring a new object as const, if we then use a
for .. in
structure, the type of the key is just inferred asstring
and not as the more restricted type that const defines. This causes issues especially when trying to use that key to get the corresponding property.🔎 Search Terms
is:issue for in as const
🕗 Version & Regression Information
const
⏯ Playground Link
https://www.typescriptlang.org/play?ts=4.8.0-dev.20220621#code/MYewdgzgLgBAtgTwMLmgeQEYCsYF4YDeAsAFAwwCGAXDAERQCm0AjLQDSnkY31NQBMtUgF9KEGKEhQA3KVIAzEACcYACknQYIbAGkGCGAEsw8ZKiiYsASkKdTKKZYDa2rHoQBdEaSA
💻 Code
🙁 Actual behavior
When using the key to get the prop, we are told that the prop would have type

any
because the key is of typestring
.🙂 Expected behavior
No error should be reported, as the correct inferred type for the key should be the union of the keys (i.e.
'a' | 'b'
in this case) of the const object.🤔 Workaround
"Coerce" the key type to be what we would have expected, so in this case:
The text was updated successfully, but these errors were encountered: