I was looking for a way to separate an array into 2 arrays given a validation function & found this question that helped a lot. The answer is the following:
function partition(array, isValid) {
return array.reduce(([pass, fail], elem) => {
return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
}, [[], []]);
}
const [pass, fail] = partition(myArray, (e) => e > 5);
Now I want to write the same question but now using typescript:
const separateArray = <T>(array: T[], condition: (e: T) => boolean): [T[], T[]] => {
return array.reduce(([passed, failed], elem: T) => condition(elem) ? [
[...passed, elem], failed
] : [passed, [...failed, elem]],[[],[]])
}
The above works just fine, the thing is that when I try to set the type for the first param of the reduce
function TO [T[], T[]]
I get an error:
Code:
return array.reduce(([passed, failed]: [T[], T[]] ......
Error:
Type 'T[][]' is not assignable to type '[T[], T[]]'.
Target requires 2 element(s) but source may have fewer.
I tried setting the type to [any[],any[]]
and [any, any]
but I still get the same error.
Does anyone know how can I solve this?
CodePudding user response:
Without any type assertion you can do it this way : Set the generic as the array and use a conditional type to extract the type of from the Array !
type Unpacked<T> = T extends (infer U)[] ? U : T;
const separateArray = <T extends Array<any>>(array: T, condition: (e: Unpacked<T>) => boolean): [T, T] => {
return array.reduce(([passed, failed], elem: Unpacked<T>) => {
return condition(elem)
? [[...passed, elem], failed]
: [passed, [...failed, elem]]
}, [[], []])
}
CodePudding user response:
Typescript is inferring the type of the first parameter as T[][]
based on the return value in the conditional operation: [[…passed, elem], failed]
and so on since type of either passed
or failed
isn’t defined and elem
has type T
. You can tell typescript explicitly that the type is [T[], T[]]
instead.
const separateArray = <T>(array: T[], condition: (e: T) => boolean): [T[], T[]] => {
return array.reduce(([passed, failed]: [T[], T[]], elem: T) => condition(elem) ? [
[...passed, elem], failed
] as [T[], T[]]: [passed, [...failed, elem]] as [T[], T[]],[[],[]])
}