Home > database >  TS7053: Element implicitly has an 'any' type because expression of type 'string'
TS7053: Element implicitly has an 'any' type because expression of type 'string'

Time:11-07

I got this code, which is supposed to sort items based on their first character into groups.

So assuming I got an array of item like this:

  • {name: 'Foo'}
  • {name: 'Bar'}
  • {name: 'Baz'}

The result should be like:

B: - Bar

  • Baz F: - Foo

This is my code to get this working - note that I am using a computed property which is just a convenient VueJS way to handle change on an item without having to manually watch this change:

<script lang="ts">
const computedItems = computed(() => {
    if (!items.value) return {};
    const grouped = items.value.data.reduce((r, item) => {
        let group = item.name[0];
        if (!r[group]) r[group] = {group, children: [item]}
        else r[group].children.push(item);
        return r;
    }, {});
    return Object.keys(grouped).sort().reduce(
        (obj, key) => {
            obj[key] = grouped[key];
            return obj;
        },
        {} as Record<string, { group: string, children: Item[] }>
);
});
</script>

Now I get thes warning:

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.   No index signature with a parameter of type 'string' was found on type '{}'.

This is shown for:

if (!r[group]) r[group]...
else r[group]...

and

obj[key] = grouped[key];

The data itself is coming from this api-call:

type ItemResult = { data: ItemData[], links?: any, meta?: any };


const {
    data: items,
} = await useLazyAsyncApi<ItemResult>(`/api/item`);

The ItemData is just a simple type:

export type ItemData = {
    uuid: string;
    company: App.Domain.Company.Data.CompanyData;
};

export type CompanyData = {
    uuid: string;
    name: string;
    url: string | null;
    phone: string | null;
    email: string | null;
    created_at: string;
    deleted_at: string | null;
};

My question is: Why can't an expression of type 'string' be used as index here and how can I avoid this error?

One thing: The code actually works. It's "just" ts complaining.

CodePudding user response:

I assume you're missing a type on your first reduce() call, as Typescript cannot know that your {} reduce initializer is of type Record<string, { group: string, children: Item[] }> :

    const grouped = items.value.data.reduce((r, item) => {
        let group = item.name[0];
        r[group] = r[group] || {group, children: []}
        r[group].children.push(item);
        return r;
    }, {} as Record<string, { group: string, children: Item[] }>); // <- HERE
    return Object.keys(grouped).sort().reduce(
        (obj, key) => {
            obj[key] = grouped[key];
            return obj;
        },
        {} as Record<string, { group: string, children: Item[] }>
    );

Aside from your question, you can sort() your data first, which will avoid a second pass on grouped result :

    const grouped = items.value.data
       .sort((i1, i2) => i1.name.localeCompare(i2.name))
       .reduce((r, item) => {
          let group = item.name[0];
          r[group] = r[group] || {group, children: []}
          r[group].children.push(item);
          return r;
       }, {} as Record<string, { group: string, children: Item[] }>);
  • Related