Tslint: строго-логические-выражения не должны срабатывать для логических операторов, используемых в небулевом контексте

Созданный на 4 окт. 2017  ·  18Комментарии  ·  Источник: palantir/tslint

Сообщение об ошибке

  • __TSLint версия__: 5.7
  • __TypeScript version__: 2.5.3
  • __ Запуск TSLint через__: CLI

Линтинг кода TypeScript

// code snippet
function valueOrDefault(a?: string) {
  return a || "the default";
}

с конфигурацией tslint.json :

{
  "defaultSeverity": "error",
  "extends": [
      "tslint:all"
  ]
}

Фактическое поведение

Получение отчета о 2-х ошибках:
strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it could be undefined. Only booleans are allowed.
strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Only booleans are allowed.

Ожидаемое поведение

Об ошибках не сообщается. Я использую логический оператор || чтобы указать значение по умолчанию для параметра (я знаю, что могу использовать объявление параметра функции по умолчанию, этот фрагмент предназначен только для иллюстрации общей проблемы). boolean нигде нет: ни вход, ни выход выражения.

Fixed Bug

Самый полезный комментарий

На мой взгляд, strict-boolean-expressions должен проверять только левый операнд && и || . Эти операторы (по сути) являются сахаром для троичных: a && b равно a ? b : a , а a || b равно a ? a : b . Когда вы думаете об этом в этих терминах, игнорирование RHS имеет большой смысл, и это приведет к тому, что поведение короткозамкнутых операторов будет соответствовать поведению троичных.

Затем , если все это находится внутри if / for / while, strict-boolean-conditions может вступить в игру и проверить общее выражение. Я думаю, что это охватит все полезные случаи, и я смогу снова включить это правило.

Код, который пометил это как проблему для меня, был документированным общим шаблоном React :

function Foo(props: { showToggle: boolean }) {
  return <div>{props.showToggle && <Toggle />}</div>;
}
ERROR: 2:36 strict-boolean-expressions This type is not allowed in the operand for the '&&' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

@ajafff Его код не проходит для меня

export function valueOrDefault(a?: string) {
  return a || "the default";
}
"strict-boolean-expressions": [true, "allow-null-union", "allow-undefined-union", "allow-string", "allow-number", "allow-mix"]
ERROR: 2:15 strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

Намерение выражения является условным для LHS, поэтому мое предложение игнорировать RHS также решило бы его проблему.

Все 18 Комментарий

Мысли? Молитвы? Предложения о том, где / как начать?

@marcind, можете ли вы привести примеры того, как он должен вести себя иначе, чем

Извините, какая часть моей первоначальной заявки неясна?

Я полагаю, что моя точка зрения состоит в том, что это правило должно выполняться только в «логическом контексте». Я могу представить себе два случая:

  1. Используется в if , while или for
  2. Присваивается переменной с типом boolean .

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

  1. const a: string = potentiallyUndefinedString || "the default";
  2. const a: string | undefined = potentiallyUndefinedObject && potentiallyUndefinedObject.getString()

@marcind примеры из вашего последнего поста будут работать, если вы используете опцию "allow-undefined-union" .

Другая часть вашего запроса должна быть отдельным правилом с именем strict-boolean-conditions которое проверяет только if , for , while , do ... while и условное выражения ( x ? y : z ).
Я могу представить, что он будет проверять только тип всего условия, а не его составляющие:

function foo(a: boolean, b?: boolean) {
    if (b || a) {} // passes, result is always boolean
    if (b && a) {} // fails, result is boolean | undefined
    if (a || b) {} // fails, result is boolean | undefined
    if (a || !!b) {} // passes
}

Возможно, это может быть вариант для существующего правила вместо нового правила ...

На мой взгляд, strict-boolean-expressions должен проверять только левый операнд && и || . Эти операторы (по сути) являются сахаром для троичных: a && b равно a ? b : a , а a || b равно a ? a : b . Когда вы думаете об этом в этих терминах, игнорирование RHS имеет большой смысл, и это приведет к тому, что поведение короткозамкнутых операторов будет соответствовать поведению троичных.

Затем , если все это находится внутри if / for / while, strict-boolean-conditions может вступить в игру и проверить общее выражение. Я думаю, что это охватит все полезные случаи, и я смогу снова включить это правило.

Код, который пометил это как проблему для меня, был документированным общим шаблоном React :

function Foo(props: { showToggle: boolean }) {
  return <div>{props.showToggle && <Toggle />}</div>;
}
ERROR: 2:36 strict-boolean-expressions This type is not allowed in the operand for the '&&' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

@ajafff Его код не проходит для меня

export function valueOrDefault(a?: string) {
  return a || "the default";
}
"strict-boolean-expressions": [true, "allow-null-union", "allow-undefined-union", "allow-string", "allow-number", "allow-mix"]
ERROR: 2:15 strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

Намерение выражения является условным для LHS, поэтому мое предложение игнорировать RHS также решило бы его проблему.

Я согласен с тем, что проверка правого места && и || является ошибкой.


Я также склонен ослабить проверки для LHS && , || и операнда ! . Их следует только проверять, всегда ли выражение правдиво или всегда ложно.
Это оставляет только условия if , for , while , do ... while и условные выражения для строгой проверки, чтобы разрешить только логические значения (или все, что настроено ). Мысли @adidahiya?

В настоящее время включение этого правила с доступными параметрами конфигурации потребует нескольких дней работы с нашей базой кода. :(

Я включил его, надеясь, что это предотвратит неявное преобразование number , null или undefined в boolean . Например:

if (!!array.length) { /* ... */ }


md5-d563d6246c0e981c16f8a2b3d7f53974





md5-430ec08bab82330fa4e519419e9ad014




However I find the following uses acceptable:



md5-70351fc6fdb328ee060919d6974e2cf4



```tsx


md5-036fd2ddd516eac8e1379cdcb9ac2b9a


Я думаю, это согласуется с тем, что предлагает @marcind .

Я также склонен ослабить проверку LHS для &&, || и операнд!.

@ajafff ​​легализует ли это if (!!array.length) или if (!possiblyNull) ?

@ajafff @adidahiya есть еще какие-нибудь мысли? Я в той же ситуации, что и @ rhys-vdw.

Беззастенчиво рекламируя собственный проект:
С момента последней работы в этом выпуске я создал свой собственный линтер - проект Fimbullinter . Прочтите документацию для быстрого старта: https://github.com/fimbullinter/wotan/blob/master/packages/wotan/README.md

Он содержит правило no-useless-predicate , которое может быть тем, что вы ищете. Это комбинация strict-type-predicates и strict-boolean-expressions TSLint, но с некоторыми существенными отличиями:

В отличие от TSLint strict-type-predicates также работает без --strictNullChecks и правильно обрабатывает параметры типа и типы пустых объектов. (наверное, не так интересно людям, подписавшимся на этот выпуск)
Основное отличие от strict-boolean-expressions TSLint заключается в том, что он не требует, чтобы все было логическим (он не обнаруживает неявное принуждение). Просто требуется, чтобы каждое условие было правдивым или ложным.

Некоторые примеры:

if (0) {} // error, always falsy
if (1) {} // error, always truthy
declare let array: string[];
if (array.length) {} // no error
if (!array.length) {} // no error
if (!!array.length) {} // no error
if (array.length === undefined) {} // error, condition is always false
if (!!false) {} // 2 errors, because of the double negation of an always falsy value

declare let someString: string;
return someString || 'some default string'; // no error, because 'someString' might be falsy

declare const foo: 'bar' | 'baz';
return foo || 'bas'; // error, 'foo' is always truthy

declare let optionalFunction: (() => void) | undefined;
optionalFunction && optionalFunction(); // no error

Я хотел бы присоединиться к следующему варианту использования из моего фактического кода:

export interface ILoggingRule {
    readonly isFinal?: boolean;
    readonly loggerNamePattern?: string;
    readonly maxLogLevel?: LogLevel;
    readonly minLogLevel?: LogLevel;
    readonly target: Target;
}

// ...

/**
 * Creates an instance of LoggingRule.
 * <strong i="6">@param</strong> options Configuration options of the logging rule.
 */
public constructor(options: ILoggingRule) {
    // tslint:disable:strict-boolean-expressions
    this.isFinal = options.isFinal || false;
    this.loggerNamePattern = options.loggerNamePattern || "*";
    this.maxLogLevel = options.maxLogLevel || LogLevel.Fatal;
    this.minLogLevel = options.minLogLevel || LogLevel.Trace;
    this.target = options.target;
    // tslint:enable:strict-boolean-expressions
}

Как видите, я использую || для обозначения значений по умолчанию, если LHS оказывается неопределенным. Есть ли какой-нибудь краткий способ заставить tslint понять, что это соответствует strict-boolean-expressions ? В противном случае я вынужден использовать эти команды отключения / включения. (Удивительно, но это проблема только при включенной проверке типов, а не в VSCode.)

Это стандартное, чрезвычайно распространенное и удобное использование в JavaScript, которое определенно не должно приводить к сбою этого правила.

ИМХО, правая часть && и || не должна проверяться, чтобы допустить короткое замыкание. Это должно быть поведение по умолчанию (или, по крайней мере, должна быть опция типа allow-any-rhs ). В настоящее время я не могу использовать strict-boolean-expressions , поскольку в нашей кодовой базе много коротких замыканий.

Проверка LHS должна оставаться неизменной ИМХО, поскольку использование string или number качестве LHS может быть опасным, см. Этот пример:

function foo(x: string | number | null) {
  return x || defaultValue;
}

Это опасно, поскольку многие разработчики не поймут, что не только null но также 0 и "" вызовут возврат defaultValue .

Мне пришлось столкнуться с серьезными ошибками в моем проекте из-за того, что разработчики не приняли во внимание, что "" и 0 также являются ложными. Предотвращение такого кода - мой основной вариант использования strict-boolean-expressions .

Исправлено в https://github.com/palantir/tslint/pull/4159, просто нужен отзыв от соавтора.

Упс, просто хотел уточнить, что один из моих примеров был плохим:

const x = possiblyUndefined || 5;

Это не должно работать, потому что possiblyUndefined может быть 0 что может быть логической ошибкой. Похоже, здесь сработает пиар

include for array - это функция ES7.
Вам необходимо изменить конфигурацию ts, чтобы использовать ES7 или ESNEXT 🦄

С уважением, 🚀

@rimiti Привет, я не могу понять, о чем вы говорите, вы уверены, что разместили этот комментарий в правильной теме?

@dobesv Ой, ты прав, прости;)

исправлено # 4159, будет доступно в следующем выпуске

Была ли эта страница полезной?
0 / 5 - 0 рейтинги