web-dev-qa-db-fra.com

L'opérateur '==' ne peut pas être appliqué aux types x et y dans TypeScript 2

TypeScript Version: 2.0.2.0

Code Je sais que le code est un peu stupide, mais j'ai ce genre de tests dans mon code (faire un visiteur d'expression) et je pense vraiment qu'ils devraient pouvoir être compilés immédiatement.

var a: boolean = (true == false);
var b: boolean = (5 == 2);

Au lieu de cela, il se plaint que l'opérande égal ne puisse pas être appliqué aux types «vrai», «faux», «5» et «2». Marquez qu'ils ne sont ni booléens ni numériques, ils sont en réalité des types de «vrai», «faux», «5», «2». Je sais que les types 'string' et 'boolean' ne peuvent pas être comparés, mais bon, 5 est en fait un nombre, pas du type '5' ou est-ce que je me trompe? 

Cela compile bien. 

let x = 2;
var a: boolean = 5 == x;
var b: boolean = <number>5 == <number>2;

Est-ce que quelque chose me manque, pourquoi 5 et 2 ne sont-ils pas considérés comme du type 'numéro'?

Comportement attendu: Devrait compiler

Comportement réel: Résultat: une erreur de compilation indiquant 'Opérande' == 'ne peut pas être appliquée aux types' <premier argument> 'et' <deuxième argument> '

Background Je suis venu sur ce problème dans TypeScript, en précisant qu'il devrait en être ainsi, mais comment se fait-il? https://github.com/Microsoft/TypeScript/issues/6167

26
Lostfields

Les types littéraux présentent de nombreux avantages, car ils permettent au compilateur de rendre les types aussi étroits que possible. Votre cas d'utilisation est très rarement abordé, mais le fait de vouloir que les types soient aussi étroits que possible imprègne toute la conception de la langue. Alors oui, bien que cela rende votre vie plus difficile dans ce cas particulier, cela a du sens dans la langue dans son ensemble. Les utilisateurs devraient avoir une langue bien pire, uniquement pour supporter ce cas d'utilisation rare.

Malheureusement, vous devrez utiliser le typage explicite que vous vous proposez dans le deuxième exemple. Je ne vois pas cela être corrigé, car la majorité des utilisateurs veulent que la langue leur crie s’ils essaient de le faire. C'est probablement le signe d'un bug dans la grande majorité des cas.

8
Simon Meskens

pourquoi les 5 et 2 ne sont-ils pas considérés comme un type 'nombre' 

Ils ont le type littéral 5 et 2. par exemple. 

var x: 5; 
// can only ever be assigned to 5 
x = 5; // okay 
x = 2; // Error 

Je ne vois pas de cas d'utilisation concrète permettant de ne pas commettre d'erreur. Ceci est juste le compilateur essayant de vous aider. N'hésitez pas à créer un problème si vous voyez une motivation suffisante

10
basarat

En tant que développeur Erlang, je voyais ce genre d’erreurs dans Erlang, mais je ne savais pas ce que cela signifiait dans TypeScript. Voici un exemple qui vous aidera à comprendre le problème:

let answer: "yes" | "no" | "maybe" = "yes";
if (Math.random() > 0.5) {
    answer = "maybe";
}

if (answer === "yes") {
    console.log('yes');
}

if (answer === "no") {
    console.log('no');
}

Il ne compilera pas avec erreur:

error TS2365: Operator '===' cannot be applied to types '"yes" | "maybe"' and '"no"'.

D'abord, voici la solution

let answer = "yes" as "yes" | "no" | "maybe";

Maintenant l'explication:

Comme ce code est très simple et peut être compris à la compilation, TypeScript sait qu’il n’ya nulle part dans le code où answer pourrait devenir "no"; il n'y a donc littéralement aucune raison de vérifier si c'est le cas. Mais (comme dans Erlang), cela peut se produire pour une raison assez évidente, lorsque vous avez par exemple décidé de commenter du code de débogage qui rendait answer devenir "no". Maintenant, si nous utilisons let answer = "yes" as "yes" | "no" | "maybe"; ou let answer = <("yes" | "no" | "maybe")>"yes";, TypeScript va penser que "oui" peut être "non" même si vous ne le voyez pas dans le code. Donc pour les cas de code temporairement supprimé, il y a seconde solution:

if (0) {
    answer = "no";
}

Même si cette condition ne sera jamais vraie, elle est suffisamment "complexe" pour que le compilateur TypeScript pense qu'elle peut être vraie. Mon approche Erlang consiste à utiliser when X and not X qui serait if (x && !x) { mais au moins dans la version 2.4, vous pouvez simplement utiliser des expressions numériques.

Mais à un moment donné, le compilateur aura peut-être raison, puis solution supprimera la vérification de "no" :)

Donc, pour en revenir à la question du PO, pour que votre code soit compilé, vous devez le changer en:

var a = false;
var b = false;

Si le compilateur le sait, vous le savez probablement aussi.

4
JLarky

Face au même problème dans un scénario comme suit:

let a: string;

a === 'some-value1' && a === 'some-value2';  // <==

La deuxième ligne produit la même erreur et peut-être parce que TypeScript est intelligent suffisant pour savoir qu'un type de chaîne à un moment donné ne peut pas contenir deux (ou plus) littéraux de chaîne différents.

L'approche correcte pour l'expression ci-dessus consisterait à utiliser OR dans l'expression:

a === 'some-value1' || a === 'some-value2';  // works fine :)
0