6

I want to add an extra property to an array, but I get trouble with declaring it.

small part

const arr: string[] & {key: number} = ['123'];//ts error  Property 'key' is missing
arr.key = 10;

large part

I need to group arr by index then sort it by value

add an index to array property will be a convenience if using Object.values but not Object.entries. I know there are many approaches to do this, but I think it's much easier if I am using plain js

type Arr = {index: number, value: number};
const arr:Arr[] = []
arr.push({
    index: 10,
    value: 2
})
arr.push({
    index: 10,
    value: 1
})
arr.push({
    index: 10,
    value: 3
});
arr.push({
    index: 20,
    value: 100
});
arr.push({
    index: 20,
    value: 50
});
arr.reduce<Record<string, Arr[] & {index: number}>>((prev, curr) => {
    if(!prev[curr.index]){
        prev[curr.index] = [];//ts error Property missing
        prev[curr.index].index = curr.index;
    }
    prev[curr.index].push(curr);
    prev[curr.index].sort((a,b) => a.value - b.value);//or some insertion sort algorithm.
    return prev;
},{})
3
  • how your are suppose to be ? [{index: number, value:string}] ? Commented Aug 5, 2019 at 7:22
  • it shoule be { indexA: [{},{},{}], indexB:[{},{},{}], indexC:[{}], ... },each item in array is sorted bt its value Commented Aug 5, 2019 at 7:57
  • possible duplicate of "Extending Array in TypeScript" Commented Aug 5, 2019 at 21:03

2 Answers 2

10

An array literal can't by itself satisfy the intersection, the simplest way you could do it is to use Object.assign which returns an intersection of its arguments:

const arr: string[] & {key: number} = Object.assign(['123'], {
    key: 10
});

And in your bigger example, the same could be used:

arr.reduce<Record<string, Arr[] & {index: number}>>((prev, curr) => {
    if(!prev[curr.index]){
        prev[curr.index] = Object.assign([], {
          index: curr.index
        })
    }
    prev[curr.index].push(curr);
    prev[curr.index].sort((a,b) => a.value - b.value);//or some insertion sort algorithm.
    return prev;
},{})

playground link

Sign up to request clarification or add additional context in comments.

4 Comments

it works! TS lacks some conscience; we need to use some tricks to ensure type-safe while plain js can do directly.
I'm slightly confused about how Record<> works here. Mind explaining it a bit? as far as I know, reduce<T1,T2> has T1 whose type is the accumulator type, while T2 is the type of the original reduce array items, how is Record working here?
@briosheje Here Record is used as a dictionary type from string to Arr[] & {index: number}. reduce only takes one type parameter, the type of the accumulator.
@TitianCernicova-Dragomir Oh, thanks. I wasn't aware of reduce taking only one type argument. I personally wasn't even aware of Record, thanks for sharing!
1

Please consider the accepted answer instead.

In your small part example, the type declaration string[] & {key: number} can never be satisfied because an array of strings cannot be the same as an object with key property.

Concerning your large part example, what exactly are you trying to achieve? If you say you want to group an array by an index, and then sort it by value, do you mean that the index is kind of your primary sort criterion and value the secondary criterion? In that case, I'd suppose you write your own sorting function that takes both values into account. You'll find an example in this Stackoverflow thread.

2 Comments

first paragraph isn't true, see accepted answer
Thanks for the correction, I didn't know that this data type declaration is indeed valid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.