Skip to content

Writing a for-in loop variable with a proper subtype of string should require a type assertion #57288

Closed as not planned
@danvk

Description

@danvk

🔎 Search Terms

  • "for-in" loop keyof type assertion

🕗 Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgIICEDCyDeBYAKGWOTgC5kQBXAWwCNoBuQk5Oi6+plkhD2hlGYEAvoUIwqIBGGAB7EMhhy5ACjh0+aLAEpcPYgBsIYZAGsKZiAE85MbZmGtlUZKrPJQpTXvxFWvAoAznLGAHSGcgDm6poA2mYAumFgcgBiwAAeEAAmqjo6TiRiouIECMGmGgg5yAC8uOTIAIwANGwUAEztWgDM7TkcEADuyAAicJD5IsLKatU5hcQA9MvIgLwbgKU73ggJyakZ2bXAQZRyVUpSMvKKhEA

💻 Code

interface ABC {
    a: number;
    b: number;
    c: number;
}

function foo(abc: ABC) {
    let k: keyof ABC;
    for (k in abc) {
        console.log(abc[k].toFixed());
    }
}

const abcd = {a: 1, b: 2, c: 3, d: new Date()};
foo(abcd);  // 💥 abc[k].toFixed is not a function 

🙁 Actual behavior

TypeScript allows this code without a type assertion on k.

🙂 Expected behavior

TypeScript should require a type assertion on k, whose type really should be string. Something like:

for (const kStr in abc) {
  const k = kStr as keyof ABC;
}

The code it allows is equivalent to a type assertion but does not use the word "as".

Additional information about the issue

This has been the behavior of TS forever, but I had trouble finding an issue requesting that TS be more strict about this, rather than less.

If you want to shoot yourself in the foot, you should at least have to write a type assertion somewhere.

Incidentally, the error you get if you write let k: "a" | "b" is a bit misleading given the behavior:

function foo(abc: ABC) {
    let k: "a" | "b";
    for (k in abc) {
    //   ~ The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. (2405)
        console.log(abc[k].toFixed());
    }
}

string would be sound, but evidently TS only requires something that keyof ABC is assignable to, not string.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions