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.