Reputation: 14778
I'm trying to write some generic array utility functions, but when I try calling one from another, the compiler seems to cast the generic to any[]
and gives me this error:
Type 'any[]' is not assignable to type 'T'.
My code:
type UnwrapArray<T extends any[]> = T extends (infer G)[] ? G : never;
function removeFromArray<T extends any[]>(
array: T,
value: UnwrapArray<T>
) {
return array.filter(other => other !== value);
}
function toggleArrayValue<T extends any[]>(array: T, value: UnwrapArray<T>): T {
if(array.includes(value)) {
return removeFromArray<T>(array, value);
} else {
return [...array, value];
}
}
The specific lines giving me trouble are these:
return removeFromArray<T>(array, value);
And
return [...array, value];
I've found I can add as T
to a bunch of stuff and it will compile successfully, but it seems like the compiler should figure this out on its own.
Upvotes: 1
Views: 160
Reputation: 250056
You assume T
extends any[]
will mean T
is an array, and any new array will be assignable to T
. This is not true.
Consider the following:
const myArr = Object.assign([1, 2, 3], {
extraProp : 1
})
toggleArrayValue(myArr, 1).extraProp // ts says this should be here where is my extraProp
extends any[]
is the lower bound on what T
can be, but it can be anything that inherits array (or a tuple but that is another can of worms of why this can't work)
I am not sure at least from your sample code why you need T
to be an array. You can express what you are trying to do without this:
function removeFromArray<T>(
array: T[],
value: T
) {
return array.filter(other => other !== value);
}
function toggleArrayValue<T>(array: T[], value: T): T[] {
if (array.includes(value)) {
return removeFromArray<T>(array, value);
} else {
return [...array, value];
}
}
Maybe your actual code is more complex, if so post that (maybe in a different question) and we can see if we can find a better solution than an unsafe type assertion.
Upvotes: 2