WHITECOLOR WHITECOLOR - 1 month ago 11
TypeScript Question

TS: why can assign not valid type to generic type variable?

Not sure how how to fomulate the question, but this is the case:

interface X {
some: number
}

let arr1: Array<X> = Array.from([{ some: 1, another: 2 }]) // no error
let arr2: Array<X> = Array.from<X>([{ some: 1, another: 2 }]) // will error


(code in playground)

The error:

Argument of type '{ some: number; another: number; }[]' is not assignable to parameter of type 'ArrayLike<X>'.
Index signatures are incompatible.
Type '{ some: number; another: number; }' is not assignable to type 'X'.
Object literal may only specify known properties, and 'another' does not exist in type 'X'.


Why in first case there is no error (no type comparability check), is it by design or there is an issue for this?

Answer

Let's look at the types of the two array instances.
If we take away the type definitions:

// type of arr1 is { some: number; another: number; }[]
let arr1 = Array.from([{ some: 1, another: 2 }]);

// type of arr2 is X[]
let arr2 = Array.from<X>([{ some: 1, another: 2 }]);

(code in playground: hover the array variables to see the types)

This is because the signature for Array.from is:

from<T>(arrayLike: ArrayLike<T>): Array<T>;

The compiler doesn't complain for arr1 because it infers the generic constraint based on the value that is passed to the function.
But in the case of arr2 the generic constraint is set to X, and the type { some: number; another: number; } doesn't match it.

If you'll try to add an X to arr1:

arr1.push({ some: 3 }); 

You'll get:

Argument of type '{ some: number; }' is not assignable to parameter of type '{ some: number; another: number; }'.
  Property 'another' is missing in type '{ some: number; }'.
Comments