Reputation: 8081
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.
Upvotes: 3
Views: 198
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[]
Upvotes: 3
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[]
Upvotes: 2