Ivan V.
Ivan V.

Reputation: 8081

Typing a function that wraps any argument in to an array

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

Upvotes: 3

Views: 198

Answers (2)

jperl
jperl

Reputation: 5112

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

Upvotes: 3

Serhii Holinei
Serhii Holinei

Reputation: 5864

You can try function overload:

function wrapInArray<T extends any[]>(data: T): T;
function wrapInArray<T>(data: T): T[];
function wrapInArray<T>(data: T):T | T[]{
  return Array.isArray(data)? [...data]:[data] 
}

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

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

TS Playground

Upvotes: 2

Related Questions