Skip to content

incorrect type using keyof and for..in #49882

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

Open
hrldcpr opened this issue Jul 12, 2022 · 2 comments
Open

incorrect type using keyof and for..in #49882

hrldcpr opened this issue Jul 12, 2022 · 2 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@hrldcpr
Copy link

hrldcpr commented Jul 12, 2022

Bug Report

It's possible to declare a key variable as a keyof before a for..in loop with no errors (even with strict mode enabled), even though it takes on values outside of that type.

For example in the following code, key is able to have the type keyof A even though it takes on other values:

interface A { x: string; }
interface B extends A { y: string; }

const b: B = { x: 'foo', y: 'bar' };
const a: A = b;

let key: keyof A;
for (key in a) { // <-- this line should be an error in my opinion
  if (key === 'x') {
    console.log('expected key', key);
  } else {
    // here `key` has type `never`
    console.log('unexpected key!', key);
  }
}

If you remove the keyof A type annotation, then key has the correct type string.

If you try using other incorrect types, such as let key: 'z'; or let key: number; then the error The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. (2405) correctly appears. So it seems wrong to me that only this particular incorrect type is allowed.

Also, this behavior disagrees with how the types of Object.keys() (discussed in #12253) and for..in (discussed in #12314) intentionally avoid the mistake of having keyof types.

🔎 Search Terms

keyof, for..in, key type

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about keyof and for..in

⏯ Playground Link

Playground link with relevant code

💻 Code

interface A { x: string; }
interface B extends A { y: string; }

const b: B = { x: 'foo', y: 'bar' };
const a: A = b;

let key: keyof A;
for (key in a) { // <-- this line should be an error in my opinion
  if (key === 'x') {
    console.log('expected key', key);
  } else {
    // here `key` has type `never`
    console.log('unexpected key!', key);
  }
}

🙁 Actual behavior

for (key in a) { does not have a type error

🙂 Expected behavior

for (key in a) { should have the error The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. (2405), as it does for other incorrect types.

@hrldcpr hrldcpr changed the title can easily get incorrect type using keyof and for..in incorrect type using keyof and for..in Jul 12, 2022
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Jul 12, 2022
@jcalz
Copy link
Contributor

jcalz commented Jul 16, 2022

Note that people seem to be using this as a workaround to being unable to (unsoundly) annotate or assert in block scope. It is mentioned in this comment on #3500 and I've seen it pop up occasionally ever since. I'm not saying it's a good thing, but fixing it might be considered a breaking change.

@hrldcpr
Copy link
Author

hrldcpr commented Jul 16, 2022

@jcalz ah yeah I noticed that too, in fact it's probably where I learned about this. Thanks for finding the relevant link.

I personally think it's a bug, and that people using it as a workaround just leads to unsafe code. And since it doesn't change js output, but just compile-time errors, it doesn't seem like a particularly bad breaking change to me.

But I don't know this project's general policy on introducing new compile-time errors so you may be right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants