ОБНОВЛЕННЫЙ ВОПРОС (один основной вопрос)
Учитывая приведенный ниже фрагмент кода, почему тип сужается при объявлении константы как Version
, но не для той, которая объявлена как number
?
type Version = 1 | 2 | 3;
const v: Version = 3;
if (v === 2) console.info('v equals 2'); // Fails compilation with "This comparison appears to be unintentional
// because the types '3' and '2' have no overlap."
const n: number = 3;
if (n === 2) console.info('n equals 2'); // No compile error
ОРИГИНАЛЬНЫЙ ПОСТ
Учитывая фрагмент кода ниже:
...types '3' and '2'...
, а не ...types 'Version' and '2'
?type Version = 1 | 2 | 3;
const v: Version = 3;
if (v > 2) console.info('v is greater than 2');
if (v === 3) console.info('v equals 3');
if (v === 2) console.info('v equals 2'); // Fails compilation with "This comparison appears to be unintentional
// because the types '3' and '2' have no overlap."
• Пожалуйста, отредактируйте это, чтобы задать один основной вопрос , иначе он рискует закрыться со словами «Требуется больше внимания: в настоящее время этот вопрос включает несколько вопросов в один. Он должен быть сосредоточен только на одной проблеме». • TypeScript имеет сужение присваивания, поэтому v
относится к типу 3
. Это ключ к ответу на оба вопроса, но какой из них вы хотите здесь задать?
@STerliakov, это скорее недоделанный пример. Отлично работает, если код был близок к реальному: Playground Link Но пример просто не настоящий, если указать постоянное значение.
@jcalz Я ищу ответ о том, как компилятор TypeScript обрабатывает сравнения типов числовых литералов, и задаю два подвопроса, чтобы прояснить ситуацию. Лично я думаю, что вопрос был бы менее ясен, если бы я пропустил один из них.
@Christian AFAIK компилятор в настоящее время не реализует необходимую арифметическую логику для сравнения типов в выражениях, которые используют операторы неравенства (например, >
) — поэтому вы можете заменить любой тип числа в операции неравенства, и компилятор это разрешит. Однако арифметика не требуется компилятору для моделирования строгого равенства сравнений типов.
true
или удалено, если false
).
Поведение >
и поведение ===
по сути независимы (последний не является числовым оператором как таковым), так что это действительно похоже на два разных вопроса в одном. Если вы хотите оставить их обоих здесь, это ваша прерогатива, но он предлагает ответы, в которых кто-то обращается к одному, но не к другому (ответ ниже, похоже, ничего не говорит вам о >
и о том, почему его не волнует «перекрытие»). ). Если это будет отредактировано, чтобы задать один вопрос узкого круга, я вернусь к нему. В противном случае, удачи!
@jcalz, честно, я постараюсь сузить вопрос (без каламбура)
Когда TypeScript видит const v: Version = 3;
, он игнорирует Version
и определяет тип как тип числового литерала 3
.
Если v
есть 3
:
(3 > 2)
Никаких ошибок(3 === 3)
Никаких ошибок(3 === 2)
Ошибка «3» и «2» не пересекаются.В следующем примере v
— это параметр функции, который выводится как Version
, а не 3
. Все работает так, как и следовало ожидать, без ошибок.
type Version = 1 | 2 | 3;
function test(v: Version) {
if (v > 2) console.info('v is greater than 2'); // No errors
if (v === 3) console.info('v equals 3'); // No errors
if (v === 2) console.info('v equals 2'); // No errors
}
test(3);
// Logs:
// "v is greater than 2"
// "v equals 3"
При использовании const v: Version = 3
TS сужается от Version
до 3
. Тогда анализ потока управления в каждом операторе if
в некоторых случаях сужается до never
.
const v: Version = 3;
if (v > 2) {
type t = typeof v; // 3
}
if (v === 3) {
type t = typeof v; // 3
}
if (v === 2) {
type t = typeof v; // never
}
if (v !== 3) {
type t = typeof v; // never
}
if (v !== 2) {
type t = typeof v; // 3
}
При использовании const v: number = 3;
TS НЕ сужается от number
до 3
. Тогда анализ потока управления не сможет сузиться number
до более конкретного типа.
const v: number = 3;
if (v > 2) {
type t = typeof v; // number
}
if (v === 3) {
type t = typeof v; // number
}
if (v === 2) {
type t = typeof v; // number
}
if (v !== 3) {
type t = typeof v; // number
}
if (v !== 2) {
type t = typeof v; // number
}
Нет. (3 !== 2)
дает вам типы «3» и «2» без перекрытия (как и ожидалось), а (3 !== 3)
работает без ошибок, как и (3 === 3)
. Если это правда или ложь, это не имеет никакого отношения к ошибке. Управляется перекрытием или неперекрытием.
Вы правы, я могу привести к путанице. Я удалил его сейчас. Спасибо!
Итак, тип «сужен» до буквального типа 3
. Но, скажем, я бы объявил v
как число, т. е. const v: number = 3;
, тогда я не получаю никаких ошибок компиляции, так что теперь нет сужения?
Сужение, вызывающее проблему, происходит в объявлении переменной. Я добавил более подробную информацию к ответу.
спасибо за объяснение. Но тогда почему в одном случае оно сужается, а в другом нет?
Именно так команда TypeScript решила это реализовать. Они рассматривают варианты использования, прежде чем реализовывать функцию, и в этом случае они, вероятно, определили, что когда люди используют типы числовых литералов вместо просто чисел, они, вероятно, действительно хотят сузиться до точного типа числовых литералов. Поэтому они сделали числовой литерал более агрессивным при сужении.
Еще один чрезмерный вывод со стороны TypeScript. Очевидно, он игнорирует вашу
Version
аннотацию и на основании константностиv
делает вывод, что это тип3
, а неVersion
, только проверяя, что 3 можно назначитьVersion
.