mhchem
mhchem

Reputation: 326

Type inference in for ... in loop

TypeScript's inference is very good. However, this example does not work as expected and needs a //@ts-ignore.

for (const p in obj) {
    if (p !== 'staticCounter' && p !== 'staticProperty') {
        //@ts-ignore
        delete obj[p];
    }
}

Without ignore, I get the error

const p: string Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Obj'. No index signature with a parameter of type 'string' was found on type 'Obj'.ts(7053)

and obj is of type

interface Obj {
    a?: string;
    o?: string;
    b?: string;
    ...
}

While the idea is easy to grasp, I think it will not be easy to implement into TypeScript. A "Can be a key for obj" type is not what the type system supports.

But can this be improved on my side? I don't like //@ts-ignores.

I am not looking for other ways to achieve the same thing. I chose this way, because it proved faster than creating a new object and assigning it the two new properties.

Upvotes: 2

Views: 942

Answers (2)

0Valt
0Valt

Reputation: 10345

This is a well-known limitation of TypeScript. The most recent issue asking to narrow string type to keyof of the object being iterated is presently open and awaits more feedback. Should you want to see it implemented, please go there, put a "like" on the issue and optionally provide a comment explaining your use case.

In the meantime an alternative to declaring the variable outside the for...in loop is to type cast:

interface Obj {
    a?: string;
    o?: string;
    b?: string;
}

const obj : Obj = {
    a: "John",
    b: "Mary"
};

for(const p in obj) {
  delete obj[<keyof Obj>p];
}

Upvotes: 1

CD..
CD..

Reputation: 74096

You can put a type annotation like this:

let p: keyof Obj
for (p in obj) {
.
.
.

Upvotes: 1

Related Questions