Typescript: вывод типа с объединением типов и тернарным оператором - PullRequest
0 голосов
/ 13 ноября 2018

Следующий машинописный код компилируется просто отлично:

let x: 0 | 1 = 0;

console.log(x);

const r = [true, false];
for (const y of r) {
    if (y || (x !== 1)) {
        x = 1;
    } else {
        x = 0;
    }

    console.log(x);
}

Однако этот код, который семантически эквивалентен, не:

let x: 0 | 1 = 0;

console.log(x);

const r = [true, false];
for (const y of r) {
    x = ((y || (x !== 1)) ? 1 : 0);
    console.log(x);
}

Ошибка для x !== 1:

7:17 error TS2367: This condition will always return 'true' since the types '0' and '1' have no overlap.

В обоих случаях выполнение скомпилированного результата дает ожидаемый результат, показывающий, что x фактически принимает значения 0 и 1:

0
1
0

Я понимаю, что ошибка связана с тем, что компилятор сузил тип 0 | 1 до 0 во втором случае. Однако, просто взглянув на код, становится ясно, что может быть тем, что x присваивается 1 (даже без учета условия). Таким образом, я ожидаю, что вывод типа примет наиболее общий тип, если явно не указано иное (как это происходит в первом примере). Фактически, в строке 1 я явно указываю компилятору, что мне нужен более общий тип: let x: 0 | 1.

Так что мой вопрос будет, если есть разумная причина, почему вывод типа ведет себя по-разному в случае троичного оператора?

1 Ответ

0 голосов
/ 13 ноября 2018

Ошибка на самом деле, потому что компилятор сузил тип x до 0.

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

Пример, где тип x вынужден быть 0 | 1, а не компилятором, сужающим его до нуля:

let x = 0 as 0 | 1;

console.log(x);

const r = [true, false];
for (const y of r) {
    x = ((y || (x !== 1)) ? 1 : 0);
    console.log(x);
}
...