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
CodePudding user response:
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 });