Tslint: Las expresiones booleanas estrictas no deben activarse para los operadores lógicos utilizados en un contexto no booleano.

Creado en 4 oct. 2017  ·  18Comentarios  ·  Fuente: palantir/tslint

Informe de error

  • __TSLint versión__: 5.7
  • __Versión de TypeScript__: 2.5.3
  • __Ejecutando TSLint vía__: CLI

El código de TypeScript está entretejido

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

con tslint.json configuración:

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

Comportamiento real

Obteniendo informe de 2 errores:
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.

Comportamiento esperado

No se informa de errores. Estoy usando el operador lógico || para proporcionar un valor predeterminado para el parámetro (sé que podría usar una declaración predeterminada de parámetro de función, el fragmento es solo para ilustrar el problema general). No hay boolean en juego en ningún lugar: ni la entrada ni la salida de la expresión.

Fixed Bug

Comentario más útil

En mi opinión, strict-boolean-expressions solo debería marcar el operando izquierdo de && y || . Esos operadores son (esencialmente) azúcar para ternarios: a && b es igual a a ? b : a , y a || b es igual a a ? a : b . Cuando lo piensa en esos términos, ignorar el RHS tiene mucho sentido, y alinearía el comportamiento de los operadores en cortocircuito con el comportamiento de los ternaries.

Entonces , si todo está dentro de un if / for / while, strict-boolean-conditions podría entrar en juego y verificar la expresión general . Creo que esto cubriría todos los casos útiles y podría volver a activar esta regla.

El código que marcó esto como un problema para mí fue este patrón de React común documentado:

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 Su código no me pasa el linter, incluso con todas las opciones de la regla habilitadas, debido a la constante RHS:

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.

La intención de la expresión está condicionada a la LHS, por lo que mi propuesta de ignorar la RHS también resolvería su problema.

Todos 18 comentarios

¿Pensamientos? ¿Oraciones? ¿Sugerencias sobre dónde y cómo empezar?

@marcind ¿ puede proporcionar ejemplos sobre cómo debería comportarse de manera diferente a cambiar la regla?

Lo siento, ¿qué parte de mi presentación inicial no está clara?

Supongo que mi punto es que esta regla solo debería ejecutarse en un "contexto booleano", puedo pensar en dos casos:

  1. Usado en un if , while o for
  2. Asignado a una variable escrita como boolean .

La regla no debería ejecutarse cuando intento proporcionar un valor predeterminado o una evaluación de cortocircuito

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

@marcind, los ejemplos de su última publicación funcionarían si usa la opción "allow-undefined-union" .

La otra parte de su solicitud debe ser una regla separada llamada strict-boolean-conditions que solo verifica if , for , while , do ... while y condicional expresiones ( x ? y : z ).
Puedo imaginar que solo verificaría el tipo de la condición completa y no sus componentes:

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
}

Quizás esta pueda ser una opción para la regla existente en lugar de una nueva regla ...

En mi opinión, strict-boolean-expressions solo debería marcar el operando izquierdo de && y || . Esos operadores son (esencialmente) azúcar para ternarios: a && b es igual a a ? b : a , y a || b es igual a a ? a : b . Cuando lo piensa en esos términos, ignorar el RHS tiene mucho sentido, y alinearía el comportamiento de los operadores en cortocircuito con el comportamiento de los ternaries.

Entonces , si todo está dentro de un if / for / while, strict-boolean-conditions podría entrar en juego y verificar la expresión general . Creo que esto cubriría todos los casos útiles y podría volver a activar esta regla.

El código que marcó esto como un problema para mí fue este patrón de React común documentado:

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 Su código no me pasa el linter, incluso con todas las opciones de la regla habilitadas, debido a la constante RHS:

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.

La intención de la expresión está condicionada a la LHS, por lo que mi propuesta de ignorar la RHS también resolvería su problema.

Estoy de acuerdo en que comprobar el RHS de && y || es un error.


También me inclino a relajar los cheques para el LHS de && , || y el operando de ! . Estos solo deben comprobarse si la expresión es siempre verdadera o siempre falsa.
Eso deja solo las condiciones de if , for , while , do ... while y expresiones condicionales para la comprobación estricta para permitir solo booleanos (o cualquier otra cosa que esté configurada ). Pensamientos @adidahiya?

Actualmente, habilitar esta regla con las opciones de configuración disponibles requeriría días de trabajo con nuestra base de código. :(

Lo habilité con la esperanza de que evitara la conversión implícita de number , null o undefined en boolean . Por ejemplo:

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


md5-d563d6246c0e981c16f8a2b3d7f53974





md5-430ec08bab82330fa4e519419e9ad014




However I find the following uses acceptable:



md5-70351fc6fdb328ee060919d6974e2cf4



```tsx


md5-036fd2ddd516eac8e1379cdcb9ac2b9a


Creo que esto concuerda con lo que sugiere @marcind .

También me inclino a relajar los controles del LHS de &&, || y el operando de!.

@ajafff ¿legalizaría esto if (!!array.length) o if (!possiblyNull) ?

@ajafff @adidahiya ¿ Alguna idea adicional aquí? Estoy exactamente en la misma situación que @ rhys-vdw.

Publicidad descaradamente mi propio proyecto:
Desde mi última actividad en este número creé mi propio linter, el proyecto Fimbullinter . Lea los documentos para un inicio rápido: https://github.com/fimbullinter/wotan/blob/master/packages/wotan/README.md

Contiene una regla no-useless-predicate , que podría ser lo que está buscando. Es una combinación de strict-type-predicates y strict-boolean-expressions de TSLint, pero con algunas diferencias importantes:

A diferencia de strict-type-predicates TSLint, también funciona sin --strictNullChecks y maneja correctamente los parámetros de tipo y los tipos de objetos vacíos. (probablemente no sea tan interesante para las personas suscritas a este número)
La principal diferencia con strict-boolean-expressions TSLint es que no requiere que todo sea booleano (no detecta coerción implícita). Solo requiere que todas las condiciones sean posiblemente verdaderas y falsas.

Algunos ejemplos:

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

Me gustaría intervenir con el siguiente caso de uso de mi código real:

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
}

Como puede ver, estoy usando || para indicar los valores predeterminados si el LHS no está definido. ¿Hay alguna forma concisa que haga que tslint entienda que esto se adhiere a strict-boolean-expressions ? De lo contrario, me veo obligado a usar esos comandos de activación / desactivación. (Sorprendentemente, esto es solo un problema con la verificación de tipos habilitada y no en VSCode).

Este uso es estándar y extremadamente común y conveniente en JavaScript, y definitivamente no debería hacer que esta regla falle.

En mi humilde opinión, el RHS de && y || no debe marcarse, para permitir un cortocircuito. Este debería ser el comportamiento predeterminado (o al menos debería haber una opción como allow-any-rhs ). Actualmente, no puedo usar strict-boolean-expressions , ya que hay muchos cortocircuitos en nuestro código base.

Verificar el LHS debe permanecer como está en mi humilde opinión, ya que usar string o number como LHS puede ser peligroso, vea este ejemplo:

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

Esto es peligroso ya que muchos desarrolladores no entenderán que no solo null sino también 0 y "" harán que se devuelva defaultValue .

Tuve que lidiar con errores importantes en mi proyecto, debido a que los desarrolladores no tuvieron en cuenta que "" y 0 también son falsos. La prevención de este tipo de código es mi caso de uso principal para strict-boolean-expressions .

Se corrigió en

Vaya, solo quería aclarar que uno de mis ejemplos era malo:

const x = possiblyUndefined || 5;

Eso no debería funcionar porque possiblyUndefined podría ser 0 que podría ser un error lógico. Parece que las relaciones públicas de @dobesv funcionarían aquí.

incluye para matriz es una característica de ES7.
Necesita cambiar su configuración para usar ES7 o ESNEXT 🦄

Saludos, 🚀

@rimiti Hola, no puedo entender a qué te refieres, ¿estás seguro de que publicaste ese comentario en el hilo correcto?

@dobesv Oh, lo siento;)

corregido por # 4159, estará disponible en la próxima versión

¿Fue útil esta página
0 / 5 - 0 calificaciones