TypeScript: Compilation fails because tsc incorrectly believes "types 'A' and 'B' have no overlap"
TypeScript Version: 3.2.4
Search Terms: generics, strict equality, overlap
Code
Here is a function I wrote, to serve as a repro case.
export function arraysEqual<A, B>(a: A[], b: B[]): boolean {
if(a.length !== b.length) return false;
for(let i = 0; i < a.length; i++) {
if(a[i] !== b[i]) return false;
}
return true;
}
Expected behavior:
The function compiles. It accepts two arrays of any two types and performs a strict equality check on their elements, whether A and B are the same type or not.
Actual behavior:
Compilation error on the line if(a[i] !== b[i]) return false; -
This condition will always return ‘true’ since the types ‘A’ and ‘B’ have no overlap.
A and B could very well be the same type. The error isn’t logical.
I will probably just rewrite it to take a single generic parameter T and both arrays will be of type T[], since the function should work just as well for me in this case. But I still believe that this behavior qualifies as a bug.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 17 (2 by maintainers)
If we think about generic functions as C+±style templates where we just rewrite the function body in terms of the template arguments and then see if that new instantiated body typechecks, then
arraysEqual<string, string>would be a valid instantiation, butarraysEqual<string, number>would be an invalid instantiation.But this is the whole point – if you intended for the two type parameters to have the same-ish type, then you didn’t need two type parameters in the first place. So your intent of having two type parameters must have been that
arraysEqual<string, number>was an legal instantiation, therefore it’s the body of the function that has an error.Duplicate of #17445
Type 'number' is not assignable to type 'string & number'.is a better error message than
Type 'number' is not assignable to type 'never'.Based on your description, it sounds like you don’t actually care what the types of the arrays are, just that they’re both arrays - at which point you gain nothing from the generic and could get the same result by declaring the parameters as
any[](orunknown[]).Using a single type parameter overall works the best from a type-checking POV too:
As long as the types are related, the call typechecks. If they are completely unrelated, the call is almost surely a mistake and the compiler flags it as such.