Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typing a function that wraps any argument in to an array

Tags:

typescript

I'm trying to properly type a function that takes an argument and wraps it into an array, however, I can't get the typings to work properly.

function wrapInArray<T>(data:T):T extends Array<infer K>? K[]: T[]{
  
  return Array.isArray(data)? [...data]:[data] 
  // ^ Type '(T & any[])[number][]' is not assignable to type 'T extends (infer K)[] ? K[] : T[]'
}

const a = wrapInArray('test') // string[]

const b = wrapInArray([1,2]) // number[]

The function works correctly, and if I try to use the function, typescript correctly infers the return type. Now I'm wondering why I'm getting an error in the function declaration itself.

TS Playground

like image 945
Ivan V. Avatar asked Nov 21 '25 19:11

Ivan V.


1 Answers

This is due to the nature of the isArray function. It's typed like this:

isArray(arg: any): arg is any[];

So when it's true, the arg is any[] says that data is any[] but you also said it was T so you end up with T & any[]...

How about (no need for overloading and bonus, we don't have to specify what the function returns, we'll let Typescript infer that for us):

function wrapInArray<T>(data: T | T[]){ //function wrapInArray<T>(data: T | T[]): T[]
  if (Array.isArray(data)) {
    // (parameter) data: T[]
    // T was either T | T[] but it's an array, we're left with only T[]
    return [...data]
  } else {
    // (parameter) data: T
    // data was either T | T[] but it's not an array so we're left with T
    return [data] // we return [T]
  }
}

const a = wrapInArray('test') // string[]

const b = wrapInArray([1,2]) // number[]

TS Playground

like image 193
jperl Avatar answered Nov 24 '25 19:11

jperl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!