I am trying to write a method in TypeScript to flatten and pick elements of paginated outputs. A demonstrative example is:
const paginatedOutput: { results: number[], page: number, meta: string[] }[] = [{ page: 1, results: [1, 2, 3], meta: ['a', 'b', 'c'] }, { page: 2, results: [3, 4, 5], meta: ['d', 'e', 'f'] }];
flattenAndPick(paginatedOutput, ['results', 'meta']);
// Output:
//
// {
// results: [1, 2, 3, 4, 5, 6],
// meta: ['a', 'b', 'c', 'd', 'e', 'f']
// }
So the method flattenAndPick
concatenates the array-type elements of objects inside an array.
The generic types and method I’ve come up with so far to solve this problem are:
/**
* Generic type which takes an object `T` and a type `K` and returns a type
* which is an object with only those properties of `T` which are of type `K`.
*
*
* Example usage:
* ```
* type A = { a: string, b: number };
*
* type B = PickByType<A, number>
*
* const b: B = { a: '1', b: 2 } // Error
*
* const b2 = { b: 2 } // Allowed
* ```
*/
type PickByType<Obj, Type> = {
[key in keyof Obj as Obj[key] extends Type | undefined ? key : never]: Obj[key];
};
This generic type will be used to extract those properties from the underlying array objects which are themselves arrays, as these represent the results of the pagination to later be concatenated together.
The method for doing the picking and concatenating is:
const flattenAndPick = <T extends object, K extends keyof PickByType<T, any[]>>(
array: T[],
properties: K[],
): Partial<PickByType<T, any[]>> => {
// Initialise an object which is just the underlying array object with only its array-type
// properties
const pickedObject: Partial<PickByType<T, any[]>> = {};
// Iterate over selected properties and initialise empty arrays for these properties
properties.forEach((property) => {
pickedObject[property] = [] as T[K]; // <-- Note the assertion here - want to remove this
});
array.forEach((element) => {
properties.forEach((property) => {
pickedObject[property] = (pickedObject[property] as any[]).concat(element[property]) as T[K]; <-- and these, although I suspect its the same issue as above
});
});
return pickedObject;
};
I’m struggling to remove the type assertions in the above method. The error without the first assertion is Type 'undefined[]' is not assignable to type 'T[K]'
.
PickByType
seems to work as expected:
type A = { a: string; b: number; c?: number; d: string[] };
type B = PickByType<A, any[]>;
type C = keyof B;
type D = { [key in C]: B[key] };
type E = C[];
const d: D = { a: '1' }; // Error
const d2: D = { b: 2, a: '1' }; // Error
const d3: D = {}; // Error
const d4: D = { b: 2: 'd': ['a'] }; // Error
const d5: D = { d: ['a'] }; // Fine
So why can I not initialise pickedObject[property] = []
in flattenAndPick
? It seems to me that T[K]
should extend any[]
. Any links to docs instructive of the underlying issue would also be appreciated.
jack-br0wn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.