Je travaille sur un morceau de code dans Typescript et je suis tombé sur ce problème ci-dessous que je n'arrive pas à comprendre pourquoi cela se produit.

Le bloc de code ci-dessous déclenche une erreur Argument of type 'string | number' is not assignable to parameter of type 'never' à la compilation.

interface A {
    x: number | string
}

const a1: A[] = [{x: 1}, {x: 'a'}]
const b: number[] | string[] = ['a', 'b']

const a2 = a1.filter(a => b.includes(a.x))

Toutefois; si je devais utiliser (number | string)[] lors de la déclaration/attribution de b, cela fonctionne bien.

J'ai vérifié le fichier de définition pour includes (Array<T>.includes(searchElement: never, ...), mais cela n'avait pas de sens non plus car je pensais que le générique T engloberait number[] | string[].

J'apprécierais si quelqu'un pouvait expliquer pourquoi le Array<T> ne couvre pas number[] | string[] mais couvre (number | string)[].

1
grkmk 9 nov. 2020 à 21:38

1 réponse

Meilleure réponse

Le type que vous avez défini pour b est number[] | string[]. Cela signifie que son type sera soit un tableau de nombres (number[]) ou un tableau de chaînes (string[]) - qui dépend exactement de les données avec lesquelles vous initialisez la variable.

Quand vous faites:

const b: number[] | string[] = ['a', 'b'];

Vous définissez en fait son type comme string[] - cette variable b n'a plus rien à voir avec les nombres et est simplement un tableau de chaînes.

Ensuite, vous allez de l'avant et faites :

const a2 = a1.filter(a => b.includes(a.x));

Ainsi, pour chaque valeur de a1 - qui peut être un string ou un number, vous vérifiez si elle existe dans le tableau b. Et comme expliqué ci-dessus, b est un tableau de chaînes uniquement. Et vous ne pouvez pas passer un number | string à includes(), qui pour ce tableau n'attend qu'un argument string (ce tableau est Array<string>). D'où l'erreur du compilateur.


Maintenant, pour l'autre cas, vous suggérez :

const b: (number | string)[] = ['a', 'b'];

Cela définit un tableau du type number | string, c'est-à-dire que chacun de ses éléments peut être d'un type différent - soit un number soit un string. Vous pouvez donc avoir par exemple :

const b: (number | string)[] = [1, 'b'];

Il se trouve que dans votre définition, tous vos éléments (les deux) sont du même type - string.

Maintenant, lorsque vous appelez includes(), la situation est très différente. Étant donné que votre tableau peut désormais contenir à la fois des nombres et des chaînes, include() fonctionnerait avec plaisir avec ces deux types (ce tableau est Array<number | string>), et a.x peut être les deux types.

3
Lyubomir Vasilev 10 nov. 2020 à 09:03