Оператор '==' не может применяться к типам x и y в TypScript 2

19

Версия TypeScript 2.0.2.0

код Я знаю, что код немного глуп, но у меня на самом деле есть такие тесты в моем коде (создание посетителя выражения), и я действительно думаю, что они должны летать и компилироваться сразу.

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

Вместо этого он жалуется, что равный операнд не может применяться к типам «true», «false», «5» и «2». Отметьте, что они не являются логическими или числовыми, они на самом деле являются типами «истина», «ложь», «5», «2». Я знаю, что типы 'string' и 'boolean' не могут сравниться, но hey, 5 на самом деле число, а не тип '5', или я ошибаюсь?

Это компилируется.

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

Я что-то упускаю, почему не 5 и 2 не считают типом числа?

Ожидаемое поведение: Должен компилироваться

Фактическое поведение: Результаты с компиляционной ошибкой: «Операнд» == 'не может применяться к типам «& lt; first argument & gt;»; и '& lt; second argument & gt;'

Фон Я столкнулся с этими проблемами в машинописи, определяя, что это должно быть так, но как получилось? Ссылка

    
задан Lostfields 31.08.2016 в 09:19
источник

3 ответа

6

Литеральные типы имеют много преимуществ, поскольку это позволяет компилятору сделать типы как можно более узкими. Ваш случай использования - это тот, который возникает очень редко, но желание типов быть настолько узким, насколько это возможно, пронизывает весь дизайн языка. Так что да, хотя это делает вашу жизнь труднее в этом конкретном случае, это имеет смысл на языке в целом. Пользователям придется страдать значительно хуже, просто чтобы поддержать этот один редкий случай использования.

К сожалению, вам придется использовать явный набор текста, который вы предлагаете себе во втором примере. Я не вижу, чтобы это когда-либо фиксировалось, потому что большинство пользователей хочет на язык кричать, если они попытаются это сделать. Вероятно, это признак ошибки в большинстве случаев.

    
ответ дан Simon Meskens 31.08.2016 в 09:35
  • Не могу сказать, что я согласен с этим. Когда я сравниваю переменную с литералом (например, строки или цифры), я ожидаю, что результат будет логическим, а для машинописного текста - не «кричать» на меня и потребовать, чтобы я написал какой-то сумасшедший код, чтобы заставить его работать. Следующее производит ту же ошибку, и я должен сказать, что это глупо - если (ключ! == 'shippingMethodId' || ключ! == 'shippingAddress'). Это похоже на то, что заставляет меня подумать о том, чтобы полностью отказаться от машинописного документа в пользу прямого ES6. –  Tim Hardy 16.03.2018 в 20:57
  • Бьюсь об заклад, есть и очень разумное объяснение вашей проблемы. Я предлагаю вам задать новый вопрос и связать его здесь, и я посмотрю на него. –  Simon Meskens 18.04.2018 в 08:34
9
  

почему 5 и 2 не рассматриваются как типы 'number'

Имеют литеральный тип 5 и 2 . например

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

Я не вижу фактического варианта использования для того, чтобы он не был ошибкой. Это просто компилятор, который пытается вам помочь. Не стесняйтесь создавать проблему, если вы видите достаточную мотивацию

    
ответ дан basarat 31.08.2016 в 09:32
  • Я могу видеть, что когда вы говорите, что x должен быть типом 5, но когда я использую только 5, я думал, что это тип «число». –  Lostfields 31.08.2016 в 10:29
  • @ Lostfields вы считаете, что пусть x = 5 означает, что x = 5 как число; но на самом деле это означает, что x = 5 как 5, сумасшедшая часть с тем, что вы даже можете записать let x = 5 как 3, в этот момент вы в основном отключите машинописный шрифт :), который разрешает x = 5 как любой –  JLarky 30.08.2017 в 02:36
3

Как разработчик Erlang, я использовал такие ошибки в Erlang, но не знал, что это значит в TypeScript, вот пример, который поможет вам понять проблему:

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');
}

Он не будет компилироваться с ошибкой:

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

Во-первых, вот решение

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

Теперь объяснение:

Так как этот код очень прост и может быть понят во время компиляции, TypeScript знает, что в коде код отсутствует, где answer может стать "no" , поэтому он просто говорит вам (хотя и в довольно загадочной форме), что ответ всегда не «нет», поэтому нет никаких оснований когда-либо проверять, есть ли это. Но (как в Erlang) это может произойти по вполне очевидной причине, когда вы, например, решили прокомментировать какой-то код для отладки, который делал answer , чтобы стать "no" . Теперь, если мы используем let answer = "yes" as "yes" | "no" | "maybe"; или let answer = <("yes" | "no" | "maybe")>"yes"; , он заставит TypeScript считать, что «да» может быть «нет», даже если вы не видите его в коде. Таким образом, для случая временно удалённого кода существует второе решение :

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

Несмотря на то, что это условие никогда не будет истинным, это достаточно сложно для компилятора TypeScript, чтобы думать, что это может быть правдой. Мой подход Erlang заключается в использовании when X and not X , который будет if (x && !x) { , но по крайней мере в 2.4 вы можете просто использовать выражения чисел.

Но в какой-то момент компилятор может быть прав, а затем solution должен удалить проверку "no" :)

Итак, возвращаясь к вопросу OP, чтобы скомпилировать ваш код, вам нужно изменить его на:

var a = false;
var b = false;

Если компилятор знает это, вы, вероятно, тоже это знали.

    
ответ дан JLarky 30.08.2017 в 02:31