Search code examples
typescriptreact-nativeerror-handlingtypeof

TypeScript Error: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'


My code is just warning fine, but I'm facing an Error type from Ts while accessing an element in the object using string.

    useEffect(() => {
    const categoriesResult: CategoryResult[] = Object.values(
      questions?.reduce((r, e) => {
        const k = e.category.id;
        if (!r[k as keyof object])
          return r[k].totalCount += 1;
      }, {})
    );
    setCategories(categoriesResult);
  }, [questions]);

The error is in r[k] to be more specific.

Thanks


Solution

  • There is a lot going on here so I will unpack this line by line.

    First, let's ignore useEffect.

    Next, the assignment:

    const categoriesResult: CategoryResult[] = Object.values(
    

    This looks fine Object.values will return an array, and you expect those to be CategoryResult type.

    Ok, let's tackle the entire reduce block:

    questions?.reduce((r, e) => {
      const k = e.category.id;
      if (!r[k as keyof object])
        return r[k].totalCount += 1;
    }, {})
    

    Your array of questions is to be reduced to an object {}.

    First issue, you need to return r always, so let's make the code this:

    questions?.reduce((r, e) => {
      const k = e.category.id;
      if (!r[k as keyof object]) {
        r[k].totalCount += 1;
      }
      return r
    },{})
    

    Without returning r you will not reduce, you will have an empty object.

    Next, r, starts it's life being equal to {} - an object - hence the error - string can't be used to index type {}

    There is some valid code below for what you are trying to achieve, in this code, the type of {} is set explicitly so that it knows the object has string keys, and values of CategoryResult types:

    // The result type
    type CategoryResult = {
      totalCount: number;
    };
    
    // Some example questions
    const questions = [
      {
        category: {
          id: "How should this work?",
        },
      },
      {
        category: {
          id: "Does that make sense?",
        },
      },
      {
        category: {
          id: "Does that make sense?",
        },
      },
    ];
    
    // A count on questions
    const questionCounts = questions?.reduce(
      (r, e) => {
        const k = e.category.id;
    
        if (r[k] === undefined) {
          r[k] = {
            totalCount: 1,
          };
        } else {
          r[k].totalCount += 1;
        }
    
        return r;
      },
      // The type of the questions count accumulator in the reduce
      {} as Record<string, CategoryResult>
    );
    
    const categoriesResult: CategoryResult[] = Object.values(questionCounts);
    
    console.info("result", { categoriesResult });