tnkh
tnkh

Reputation: 1839

How to declare types for empty object array with typescript?

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?

Upvotes: 0

Views: 2902

Answers (2)

Carlo Corradini
Carlo Corradini

Reputation: 3425

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

Upvotes: 1

jlouzado
jlouzado

Reputation: 502

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

Upvotes: 1

Related Questions