Reputation: 131
How can I describe result
and acc
type for the following code?
const arr = ['a', 'b', 'c'] as const;
const result = arr.reduce((acc, item, idx) => {
return {
...acc,
[item]: idx,
}
}, {});
Depends on an iteration acc
can be:
First I used this code:
type MyResult = Record<typeof arr[number], number>; //
type MyAcc = Partial<MyResult>;
But it's incorrect:
Types of property 'a' are incompatible.
Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.(2322)
Upvotes: 1
Views: 277
Reputation: 78890
Here's my approach:
type ArrayItemType<A extends ReadonlyArray<any>> = A[number];
const arr = ['a', 'b', 'c'] as const;
type KeyIndexes = Record<ArrayItemType<typeof arr>, number>;
const result = arr.reduce((acc, item, idx) => {
return {
...acc,
[item]: idx,
}
}, {} as KeyIndexes);
KeyIndexes
is effectively:
{
a: number,
b: number,
c: number
}
...as you can see at this playground
I realize the objection that technically the initializer and accumulator are not this type at all stages of the reduction, but TypeScript really doesn't have a way of figuring out how a partial result will become the full result, so you'll need casting at some point anyway.
Update
If you really care that the accumulator is of a different type than the result, you can adjust the types accordingly, but you'll have to do some more ugly casting:
type ArrayItemType<A extends ReadonlyArray<any>> = A[number];
const arr = ['a', 'b', 'c'] as const;
type KeyIndexes = Record<ArrayItemType<typeof arr>, number>;
const result = arr.reduce((acc: Partial<KeyIndexes>, item, idx) => {
return {
...acc,
[item]: idx,
}
}, {}) as KeyIndexes;
(see playground)
Upvotes: 2