0

Say the array is const items = [{category:'cat1', name:'name1'},{category:'cat2', name:'name2'}].

I want to construct the above array to become an object format like the following:

{
  'cat1':'name1',
  'cat2':'name2'
}

Without typescript, I can do the following to solve the problem:

const parseFunction = (items) => {
 const newObj = {};
 for (const item of items) {
   newObj[item.category] = newObj[item.name];
 }
 return newObj;
}

However with typescript below:

interface IItems{
 category: string,
 name: string
}

interface INewObj{
 'cat1': string,
 'cat2': string
}

const parseFunction = (items: IItems[]) => {
 const newObj = {} as INewObj;
 for (const item of items) {
   newObj[item.category] = newObj[item.name];
 }
 return newObj;
}

The line newObj[item.category] = newObj[item.name] throws the following TS error

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

How should I fix this?

2 Answers 2

1

Does this solution can suit your needs?

Use Record<Keys, Type> to map the unknown keys and values.

Typescript code

const items: IItems[] = [{ category: 'cat1', name: 'name1' }, { category: 'cat2', name: 'name2' }];

interface IItems {
    category: string,
    name: string
}

type NewObjType = Record<string, string>;

const parseFunction = (items: IItems[]): NewObj => {
    const newObj: NewObjType = {};

    for (const item of items) {
        newObj[item.category] = item.name;
    }

    return newObj;
}

console.log(parseFunction(items));

Javascript Snippet

"use strict";
const items = [{ category: 'cat1', name: 'name1' }, { category: 'cat2', name: 'name2' }];
const parseFunction = (items) => {
    const newObj = {};
    for (const item of items) {
        newObj[item.category] = item.name;
    }
    return newObj;
};
console.log(parseFunction(items));

PS: You made a little mistake here newObj[item.category] = newObj[item.name] since the value does not already exists in the newObj variable. I have changed to the correct assignment as follow: newObj[item.category] = item.name

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

Comments

1

In practice I'm guessing you wouldn't really know that the categories were cat1, cat2 etc, all you'd know is that they would be strings. Therefore the definition of INewObj needs to be a little more permissive.

type INewObj = {
  [key: string]: string
}

Which can be further shortened to Record<string, string>.

Playground link

You could go further and eliminate INewObj entirely by allowing Typescript to infer it for you:

Playground 2

Comments

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.