Проверьте, не превышает ли значение, которое также может быть нулевым, 4 в машинописном тексте

#typescript

Вопрос:

Как я могу проверить, если значение, инициализированное как null или число, больше 4 в машинописном тексте? см.Пример.

 years: number | null;
 

это приведет к ошибке машинописного текста «Объект, возможно, «нулевой»».

 (years > 4)
 

Комментарии:

1. Что ж, в этом нет ничего плохого… Если вы проверяли раньше и уверены, что это не null, вы можете сделать (лет! > 4), чтобы сообщить ide, что это точно не null, в противном случае проверьте на null, в общем, я бы не стал комбинировать опцию с null и числом

2. Задумывались ли вы над выражением: (years amp;amp; years > 4) ? Или даже (typeof years === "number" amp;amp; years > 4) ?

3. @CRice Да, но необходимость повторять это выражение каждый раз вызывает боль — я думаю, что OP спрашивает о том, как кодировать ограничение диапазона в качестве типа предиката- к сожалению, TS не поддерживает «реальные» типы предикатов, но вы можете использовать typedef и функцию защиты в качестве типа предиката.

4. Если мы просто пытаемся избежать повторения, то, возможно, предложение Шай будет лучшим. JS преобразуется null 0 в это сравнение, так что оно будет работать нормально, даже если years есть null . И добавление ! этого не позволит машинописному тексту жаловаться на это.

5. @Dai да, это именно то, о чем я спрашивал

Ответ №1:

Я предполагаю, что вы спрашиваете, как вы можете выразить статическое требование, которому всегда удовлетворяет параметр функции (или возвращаемое значение, или значение свойства класса) с именем x ( x is number amp;amp; x > 4 ) | null .

…который также известен как Тип предиката, Тип уточнения или Зависимый тип.

К сожалению, TypeScript (насколько мне известно) еще не поддерживает истинные типы уточнений или типы предикатов (хотя его возможности анализа потоков почти доступны), но вы почти можете достичь этого с помощью определения типа и защиты типа:

 type NumberGT4OrNull = null | ( number amp; { _isGT4: never } );

function isNumberGT4OrNull( x: unknown ): x is NumberGT4OrNull {
    if( typeof x === 'number' ) {
        return x > 4;
    }
    return false;
}
 
  • Объявление типа type NumberGT4OrNull = null | number; слишком допустимо, так как 1 , например, оно соответствует значению.
  • Что делает его сумма типа с членом набирается как never означает, что нет буквальное значение (или любое другое значение), возможной в рамках на TypeScript или JavaScript не может сравниться NumberGT4OrNull — по крайней мере, не без использования пользовательского типа-охранник isNumberGT4OrNull , который предотвращает случайное, используя любое значение не проверяется isNumberGT4OrNull в параметр, возвращаемое значение или свойство с типом NumberGT4OrNull .
    • …за исключением null , потому что в этом случае null ключевое слово находится вне типа суммы с never .
      • Но если вы хотите, чтобы для проверки требовались четные null значения, используйте type NumberGT4OrNull = ( null | number ) amp; { _isGT4: never }; .
    • Недостатком является то , что вы не можете не использовать isNumberGT4OrNull , но это не такая уж большая проблема в общей схеме вещей.

Используется так:

 function acceptsValue( value: NumberGT4OrNull ): void {
}

//

const userInput = prompt("Enter number");
acceptsValue( userInput ); // Error: userInput is a string

const userInputNumber = parseInt( userInput, 10 );
acceptsValue( userInputNumber ); // Error: userInputNumber is not NumberGT4OrNull

if( isNumberGT4OrNull( userInputNumber ) ) {
    acceptsValue( userInputNumber ); // OK! TSC knows `userInputNumber` is `NumberGT4OrNull`.
}
 

Как было сказано выше, использование never означает, что буквальное значение не будет совпадать, поэтому следующее не будет работать и приведет к ошибкам:

 acceptsValue( 3 ); // Error
acceptsValue( 4 ); // Error
acceptsValue( 5 ); // Error
acceptsValue( null ); // But this is OK
 

Но вы можете добавить (неисчерпывающий) набор постоянных значений для удобства, если хотите:

 type NumberGT4OrNull = null | ( number amp; { _isGT4: never } ) | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16;

// So now, this does work:
acceptsValue( 3 ); // Error
acceptsValue( 4 ); // Error
acceptsValue( 5 ); // OK!
acceptsValue( null ); // Also OK

const n = 17;
acceptsValue( n ); // Error
if( isNumberGT4OrNull( n ) ) {
    acceptsValue( n ); // OK!
}
 

Ссылка на игровую площадку

Комментарии:

1. @CRice Я нашел ошибку в своем ответе — acceptsValue( userInputNumber ); утверждение на самом деле отлично компилируется — я вижу, как я могу заставить его работать правильно, хм.

2. Используйте виртуальное свойство в качестве дискриминатора, таким образом, значение должно пройти через защиту типа, прежде чем его можно будет присвоить acceptsValue . НАПРИМЕР: type isNumberGT4OrNull = (number | null) amp; {_isGT4: never} .

Ответ №2:

years может быть, это число, или или может быть null . И null > 4 в этом нет никакого смысла.

Поэтому, прежде чем вы это сделаете, вы должны убедиться, что на самом деле это не null первое.

 if (years !== null) {
  const isMoreThanFour = years > 4
}
 

Игровая площадка

Комментарии:

1. Можно также объединить его в один оператор if: if (years amp;amp; years > 4) . Для ссылки: if (years) возвращает true , если years не является: null , undefined , NaN , пустой строкой '' , 0 , или false .