3

I'm trying to be cute with TypeScript and arrays and use the spread operator to essentially prepend an object to an array of objects.

Here's the setup:

Interface to define my types:

interface KeyValuePair {
  key: string;
  value: string;
}

An array of objects of type:

const kvpset: KeyValuePair[] = [
  { key: "1", value: "One" },
  { key: "2", value: "Two" },
  { key: "3", value: "Three" },
  { key: "4", value: "Four" },
  { key: "5", value: "Five" },
  { key: "6", value: "Six" },
  { key: "7", value: "Seven" },
  { key: "8", value: "Eight" },
  { key: "9", value: "Nine" },
];

My prepend typed object thingy:

const kvpzero: KeyValuePair = { key: "0", value: "Zero" };

First try:

const kvpAll: KeyValuePair[] = { kvpzero, ...kvpset };

Error in the editor:

property) kvpzero: KeyValuePair Type '{ length: number; toString(): string; toLocaleString(): string; pop(): KeyValuePair; push(...items: KeyValuePair[]): number; concat(...items: ConcatArray[]): KeyValuePair[]; concat(...items: (KeyValuePair | ConcatArray<...>)[]): KeyValuePair[]; ... 26 more ...; kvpzero: KeyValuePair; }' is not assignable to type 'KeyValuePair[]'. Object literal may only specify known properties, and 'kvpzero' does not exist in type 'KeyValuePair[]'.ts(2322)

Okay, so I'm a bit clueless. I'll try this:

const kvpzeroAsArray: KeyValuePair[] = [{ key: "0", value: "Zero" }];

and this doesn't give a "compiler error":

const kvpAll: KeyValuePair[] = { ...kvpzeroAsArray, ...kvpset };

Using tsc and node to run it (editor is Visual Studio Code). Results in a console.log() for the kvpAll object:

kvpAll is {
  '0': { key: '1', value: 'One' },
  '1': { key: '2', value: 'Two' },
  '2': { key: '3', value: 'Three' },
  '3': { key: '4', value: 'Four' },
  '4': { key: '5', value: 'Five' },
  '5': { key: '6', value: 'Six' },
  '6': { key: '7', value: 'Seven' },
  '7': { key: '8', value: 'Eight' },
  '8': { key: '9', value: 'Nine' }
}

Three things that I see here. One, the object is now an object and not an array. Two, my zero is missing.I have no idea why this doesn't work or why I can't get the expected results. Three, it's not even the same type of output I wanted. It has the property as a number with the value as the object. '0': { key: '1', value: 'One' } instead of just { key: '1', value: 'One' }.

Searching on the web, it seems that maybe the Object.assign() mechanism is a way to go.

const assignedkvp = (<any>Object).assign(kvpzeroAsArray, kvpset);

Output (via a console.log() again):

assignedkvp is [
  { key: '1', value: 'One' },
  { key: '2', value: 'Two' },
  { key: '3', value: 'Three' },
  { key: '4', value: 'Four' },
  { key: '5', value: 'Five' },
  { key: '6', value: 'Six' },
  { key: '7', value: 'Seven' },
  { key: '8', value: 'Eight' },
  { key: '9', value: 'Nine' }
]

Hmm...similar results as the spread. The object doesn't get changed as the spread changes it, but I still don't see my desired pretending result.

I'm at a loss at this point. I don't understand how I can use the spread operator or the assign function and get the desired results. I'd appreciate any insight. Here's my current solution. The brute force method:

const prePendObjectToArray = <T>(object: T, array: T[]): T[] => {
  let returnArray = [] as T[];

  if (array && array.length > 0 && object) {
    for (let i = 0; i < array.length + 1; i++) {
      if (i === 0) {
        returnArray.push(object);
      } else {
        returnArray.push(array[i - 1]);
      }
    }
  }

  return returnArray;
};

Usage:

const newArray = prePendObjectToArray(kvpzero, kvpset);
console.log(newArray);

Result:

[
  { key: '0', value: 'Zero' },
  { key: '1', value: 'One' },
  { key: '2', value: 'Two' },
  { key: '3', value: 'Three' },
  { key: '4', value: 'Four' },
  { key: '5', value: 'Five' },
  { key: '6', value: 'Six' },
  { key: '7', value: 'Seven' },
  { key: '8', value: 'Eight' },
  { key: '9', value: 'Nine' }
]

If there is a better way, I'd appreciate knowing what I'm missing.

Dan7el
  • 1,995
  • 5
  • 24
  • 46

1 Answers1

4
const kvpAll: KeyValuePair[] = { ...kvpzeroAsArray, ...kvpset };

This is not an array. You are spreading into an object.

Do:

const kvpAll: KeyValuePair[] = [ ...kvpzeroAsArray, kvpset ];
Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
  • 1
    Thank you. I was thinking I was missing something simple, and I was. That resolved my issue. – Dan7el Oct 29 '20 at 13:19