Home > Software design >  Using generic types on array.reduce function to divide array into two
Using generic types on array.reduce function to divide array into two

Time:08-16

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[]],[[],[]])
  }
  • Related