-2

I have this base type:

export interface IMyType : {
   field1: number,
   field2: number
}

I also have this "extension" type:

export interface ISelectable {
   isSelected: boolean;
}

Somewhere else, I have a function like this:

const foo = (param: (IMyType & ISelectable)[]) => { // <-- my on-the-fly "extended" type
   param[0].isSelected = ... //do whatever
}

My problem is to created the composite array:

const dataArray: IMyType[] = [{field1: 0, field2: 0}, {field1: 0, field2: 0}];
const extendedArray = [ dataArray, ...[{isSelected: false}] ]; // <-- extend!

foo(extendedArray); // <-- PROBLEM! typescript still sees extendedArray
                    //     as of type IMyType[] instead of 
                    //    (IMyType & Iselectable)[]  so it refuses this.

I'm 99% sure that I misused the spread operator (...) but right now I can't find the right syntax.

In recap, I tried the following :

const extendedArray = [ dataArray, ...[{isSelected: false}] ]; //Nope! (Makes zero sense, in the light of the comments below)
const extendedArray = [ ...dataArray, {isSelected: false} ]; //nope! (Makes zero sense, in the light of the comments below)
const extendedarray = dataArray.map (x => {isSelected: false, ...x}) //Almost correct but was missing sone syntactic sugar!

I've read this and many other answers but I can't figure it out : TypeScript add object to array with spread

jeancallisti
  • 1,046
  • 1
  • 11
  • 21
  • What value were you expecting to get? You add one value to the end of the array, equivalent to push, so the result is an array of the _union_ not the intersection of those two types. – jonrsharpe Oct 17 '22 at 08:14
  • `[ dataArray, ...[{isSelected: false}] ];` means you have an array that contains *the full array* `dataArray` as one item, and then you also add *one item* to it which is `{isSelected: false}`. For example with `dataArray = [{field1: 1, field2: 11}, { field1: 2, field2: 22}]` you'd get the following array `[ [{field1: 1, field2: 11}, { field1: 2, field2: 22}], {isSelected: false} ]` It does not modify `dataArray` to add `{isSelected: false}` to each item. Moreover, that's not possible with spread (alone). – VLAZ Oct 17 '22 at 08:14
  • I want each item in the new array to be the same as the original array, but with extra field 'isSelected' – jeancallisti Oct 17 '22 at 08:15
  • 2
    Well that's not at all what you're writing. Maybe use `.map` and spread each _object_. – jonrsharpe Oct 17 '22 at 08:16
  • 1
    "*I want each item in the new array to be the same as the original array, but with extra field 'isSelected'*" it's best to ask about that rather than [not that](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – VLAZ Oct 17 '22 at 08:16
  • So I tried this and it's still not correct synctactically : const extendedarray = dataArray.map (x => {isSelected: false, ...x}) – jeancallisti Oct 17 '22 at 08:20
  • You need `()` around the object if you want to use the short body version of an arrow function: [ECMAScript 6 arrow function that returns an object](https://stackoverflow.com/q/28770415) `dataArray.map (x => {isSelected: false, ...x})` -> `dataArray.map (x => ({isSelected: false, ...x}))` – VLAZ Oct 17 '22 at 08:21

3 Answers3

1

Bu using the spread operateor you appened elements, you do not modify the existing ones

So const extendedArray = [ dataArray, ...[{isSelected: false}] ];

The extendedArray will have two type elements: First element will be an array of IMyType , the second element will be of type { isSelected: boolean }

If you want to modify all elements in an array - use .map(). And preferably create a copy of all objects like this:

const extendedArray = dataArray.map(item => { return { ...item, isSelected: false } });

//All is ok now
foo(extendedArray);

Playground here

Svetoslav Petkov
  • 1,117
  • 5
  • 13
  • That's what I've been looking for. I failed because I thought this syntax was enough : ````const extendedarray = dataArray.map (x => {isSelected: false, ...x})```` but as some people have pointed out I need to add a few things : ```const extendedArray = dataArray.map(item => { return { ...item, isSelected: false } });``` – jeancallisti Oct 17 '22 at 08:23
  • 1
    @LouisWilke An answer that explains the problem and what it does to solve that problem is more valuable than a one-liner without any explanation at all. – Andreas Oct 17 '22 at 08:37
  • @Andreas True. I guess I shall improve that in my next answers – Louis Wilke Oct 17 '22 at 08:42
1

use spread operator

const extendedArray: (IMyType & ISelectable)[] = dataArray.map((el) => {
  return { ...el, isSelected: false };
});
-2

You can cast your array:

const extendedArray = (dataArray as (IMyType&ISelectable)[]).map( d => {d.isSelected = false; return d} );
Louis Wilke
  • 147
  • 5
  • `dataArray` _isn't_ `(IMyType&ISelectable)[]`, you're lying to the compiler; it's the result of calling `.map` that is. This claims that `d` is already the right return value and you're just overwriting the _existing_ `isSelected` prop. – jonrsharpe Oct 17 '22 at 18:49