Is there a way to more strictly type the following two functions toCsv()
and toArray()
such that typeof csv
is
[["key", "life", "goodbye"], [string, number, boolean]]
instead of
[("key" | "life" | "goodbye")[], ...(string | number | boolean)[]]
and typeof original
is the same as typeof values
instead of
{ key: any, life: any, goodbye: any }[]
I realize that iteration order of { key: 'value', life: 42, goodbye: false }
using for...in
is not guaranteed and I'm fine with that. Any consistent order that aligns keys with respective values for each row is acceptable, even if the TypeScript compiler doesn't produce the same order as runtime, since the usage doesn't rely on any particular ordering.
type Key<T> = Extract<keyof T, string>;
type Column<T> = [Key<T>, ...T[Key<T>][]];
type Columns<T> = [Key<T>[], ...T[Key<T>][][]];
function toCsv<T> (array: T[]): Columns<T> {
const columns: Column<T>[] = [];
for (const key in array[0]) {
columns.push([key, ...array.map(value => value[key])]);
}
const keys: Key<T>[] = [];
const rows: T[Key<T>][][] = array.map(() => []);
for (const [key, ...values] of columns) {
keys.push(key);
for (const [index, row] of rows.entries()) {
row.push(values[index]);
}
}
return [keys, ...rows];
}
function toArray<T> (csv: Columns<T>): T[] {
const [keys, ...rows] = csv;
return rows.map(
row => keys.reduce(
(o, key, index) => Object.assign(o, { [key]: row[index] }),
{} as Partial<T>
) as T
);
}
const values = [{ key: 'value', life: 42, goodbye: false }];
const csv = toCsv(values);
const original = toArray(csv);
Aucun commentaire:
Enregistrer un commentaire