Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid implicit 'any' type when using Object.keys in Typescript

I have an Object with keys that I've typed and I want to loop over it and maintain their type, avoiding "Element implicitly has an 'any' type because 'ContactList' has no index signature".

I know this has been discussed at length on Typescript's GitHub pages but I haven't found any solutions for what I'm trying to do here. Trying it both with enums and with unions, but I still get the error.

Example with enums (playground)

enum Names {
  Joe,
  Bill,
  Bob
}

type ContactList = {
  [key in Names]: {
    isFriend: boolean;
  }
}

const contactList: ContactList = {
  [Names.Joe]: {
    isFriend: true,
  },
  [Names.Bill]: {
    isFriend: false,
  },
  [Names.Bob]: {
    isFriend: true,
    },
};

Object.keys(contactList).forEach(name => {
    // turn on 'noImplicitAny' and get error
    console.log(contactList[name])
})

Example with unions (playground)

type Names = 'joe' | 'bill' | 'bob'

type ContactList = {
  [K in Names]: {
    isFriend: boolean;
  }
}

const contactList: ContactList = {
  joe: {
    isFriend: true,
  },
  bill: {
    isFriend: false,
  },
  bob: {
    isFriend: true,
    },
};

Object.keys(contactList).forEach(name => {
    // turn on 'noImplicitAny' and get error
    console.log(contactList[name])
})

Either way, I'm telling typescript "the only keys allowed in this object are from Names" and as far as I understand index signatures, [key in Names] should be one, so I'm not sure why I'm seeing an error. Sorry if this is a noob question, I'm a little green with TS still. Thanks.

like image 473
hello_luke Avatar asked Mar 05 '19 21:03

hello_luke


1 Answers

As Object.keys might return more properties than the object actually contains by type, the return type of it is intentionally typed as string[]. Otherwise, it would be pretty common for well-typed code to throw unexpected exceptions at runtime, as explained in this answer.

Therefore you have to make your index type work on strings:

type ContactList = {
  [key: string]: {
    isFriend: boolean;
  },
};

Or you typecast and hope for the best:

contactList[name as Names]

Also you could just:

console.log(...Object.values(contactList));
like image 183
Jonas Wilms Avatar answered Oct 19 '22 17:10

Jonas Wilms