1

The following code block returns a TypeScript error.

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; path: string; basename: string; createdOn: string; modifiedOn: string; content: string; }'.

Square brackets work fine in JavaScript (or using //@ts-ignore).

What is the right way of doing this in TypeScript?

export interface Data {
  [key: string]: {
    id: string
    path: string
    basename: string
    createdOn: string
    modifiedOn: string
    content: string
  }
}

const data = _data as Data // _data is JSON

for (let item in data) {
  for (let property in data[item]) {
    console.log(property)
    if (["createdOn", "modifiedOn"].includes(property)) {
      data[item][property] = new Date(data[item][property])
    }
  }
}

Here’s what the JSON of _data looks like.

{
  "readme": {
    "id": "3905d7917f2b3429490b01cfb60d8f5b",
    "path": "README.md",
    "basename": "README.md",
    "createdOn": "2020-02-26T12:29:26.181Z",
    "modifiedOn": "2020-02-26T12:29:26.181Z",
    "content": "<!--\nTitle: Privacy guides\nDescription: Privacy guides will be published shortly...\n-->\n\n# Privacy guides\n\nPrivacy guides will be published shortly...\n"
  },
  ...
}
2
  • So you want to access/edit createdOn and modifiedOn for each item inside your data array? Commented Feb 27, 2020 at 15:09
  • @r3dst0rm Thanks for your help. Added what the JSON looks like to the questions. I wish to iterate through the nested properties of data. Commented Feb 27, 2020 at 15:13

1 Answer 1

2

The reason is two fold:

  1. property has a string type, instead of being known as a key in the nested object
  2. data[item][property] = new Date(...) will return an error anyway, because your nested object only expect string as values

Since using .includes() or .indexOf() does not narrow the type properly, you will have to create a function that basically returns the correct keys. This serves as a type guard that will return the correct types from a union type:

function hasPossibleDateAsValue(value: string): value is 'createdOn' | 'modifiedOn' {
  return ["createdOn", "modifiedOn"].includes(value);
}

Then, you can do this without TypeScript throwing an error/warning:

for (let item in data) {
  for (let property in data[item]) {
    if (hasPossibleDateAsValue(property)) {
      data[item][property] = new Date(data[item][property]);
    }
  }
}

See proof-of-concept on TypeScript playround.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much for your help... so the issue isn’t actually in accessing nested properties but rather in how to work with or around the limitations of includes.
@sunknudsen That is correct. Typescript cannot perform typeguards using includes or indexOf. Anyway, I have updated my answer so that it’s using includes() again. It doesn’t matter if you use that or indexOf().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.