// code snippet
function valueOrDefault(a?: string) {
return a || "the default";
}
com configuração tslint.json
:
{
"defaultSeverity": "error",
"extends": [
"tslint:all"
]
}
Obtendo relatório de 2 erros:
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.
Nenhum erro sendo relatado. Estou usando o operador lógico ||
para fornecer um valor padrão para o parâmetro (eu sei que poderia usar uma declaração padrão de parâmetro de função, o snippet é apenas para ilustrar o problema geral). Não há boolean
em jogo em lugar nenhum: nem a entrada nem a saída da expressão.
Pensamentos? Orações? Sugestões sobre onde / como começar?
@marcind, você pode fornecer exemplos de como ele deve se comportar de maneira diferente de virar a regra?
Desculpe, qual parte do meu envio inicial não está claro?
Acho que meu ponto é que essa regra só deve ser executada em um "contexto booleano", posso pensar em dois casos:
if
, while
ou for
boolean
.A regra não deve ser executada quando estou tentando fornecer um valor padrão ou avaliação de curto-circuito
const a: string = potentiallyUndefinedString || "the default";
const a: string | undefined = potentiallyUndefinedObject && potentiallyUndefinedObject.getString()
@marcind os exemplos de sua última postagem funcionariam se você usar a opção "allow-undefined-union"
.
A outra parte da sua solicitação deve ser uma regra separada chamada strict-boolean-conditions
que verifica apenas if
, for
, while
, do ... while
e condicional expressões ( x ? y : z
).
Posso imaginar que apenas verificaria o tipo de toda a condição e não seus constituintes:
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
}
Talvez isso possa ser uma opção para a regra existente em vez de uma nova regra ...
Na minha opinião, strict-boolean-expressions
deve verificar apenas o operando esquerdo de &&
e ||
. Esses operadores são (essencialmente) açúcar para ternários: a && b
é igual a a ? b : a
e a || b
é igual a a ? a : b
. Quando você pensa sobre isso nesses termos, ignorar o RHS faz muito sentido e colocaria o comportamento dos operadores em curto-circuito em linha com o comportamento dos ternários.
Então , se tudo estiver dentro de um if / for / while, strict-boolean-conditions
pode entrar em ação e verificar a expressão geral . Acho que isso cobriria todos os casos úteis e eu seria capaz de ativar essa regra novamente.
O código que sinalizou isso como um problema para mim foi este padrão React comum 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 Seu código não passa o linter para mim, mesmo com todas as opções da regra habilitadas, devido ao RHS constante:
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.
A intenção da expressão é uma condição do LHS, portanto, minha proposta de ignorar o RHS também resolveria o problema dele.
Eu concordo que verificar o RHS de &&
e ||
é um bug.
Também estou inclinado a relaxar as verificações para o LHS de &&
, ||
e o operando de !
. Estes devem ser verificados apenas se a expressão é sempre verdadeira ou sempre falsa.
Isso deixa apenas as condições de if
, for
, while
, do ... while
e expressões condicionais para a verificação estrita para permitir apenas booleanos (ou qualquer outra coisa que esteja configurada ) Pensamentos @adidahiya?
Atualmente, a habilitação dessa regra com as opções de configuração disponíveis exigiria dias de trabalho com nossa base de código. :(
Eu o habilitei esperando evitar a conversão implícita de number
, null
ou undefined
em boolean
. Por exemplo:
if (!!array.length) { /* ... */ }
md5-d563d6246c0e981c16f8a2b3d7f53974
md5-430ec08bab82330fa4e519419e9ad014
However I find the following uses acceptable:
md5-70351fc6fdb328ee060919d6974e2cf4
```tsx
md5-036fd2ddd516eac8e1379cdcb9ac2b9a
Acho que isso está de acordo com o que sugere @marcind .
Também estou inclinado a relaxar as verificações do LHS de &&, || e o operando de!.
@ajafff isso legalizaria if (!!array.length)
ou if (!possiblyNull)
?
@ajafff @adidahiya mais alguma opinião aqui? Estou exatamente na mesma situação que @ rhys-vdw.
Anunciando descaradamente meu próprio projeto:
Desde minha última atividade nesta edição criei meu próprio linter, o projeto Fimbullinter . Leia a documentação para um início rápido: https://github.com/fimbullinter/wotan/blob/master/packages/wotan/README.md
Ele contém uma regra no-useless-predicate
, que pode ser o que você está procurando. É uma combinação de strict-type-predicates
e strict-boolean-expressions
do TSLint, mas com algumas diferenças importantes:
Em contraste com o strict-type-predicates
do TSLint também funciona sem --strictNullChecks
e trata corretamente os parâmetros de tipo e os tipos de objetos vazios. (provavelmente não é tão interessante para as pessoas que se inscreveram nesta edição)
A principal diferença para o strict-boolean-expressions
do TSLint é que ele não exige que tudo seja booleano (ele não detecta coerção implícita). Exige apenas que todas as condições sejam possivelmente verdadeiras e falsas.
Alguns exemplos:
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
Eu gostaria de comentar o seguinte caso de uso do meu 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 você pode ver, estou usando ||
para denotar valores padrão se o LHS for indefinido. Existe alguma maneira concisa de fazer tslint
entender que está de acordo com strict-boolean-expressions
? Caso contrário, sou forçado a usar os comandos de ativação / desativação. (Surpreendentemente, este é apenas um problema com a verificação de tipo ativada e não no VSCode.)
Esse uso é padrão e extremamente comum e conveniente em JavaScript e, definitivamente, não deve fazer com que essa regra falhe.
IMHO, o RHS de &&
e ||
não deve ser verificado, para permitir curto-circuito. Este deve ser o comportamento padrão (ou pelo menos deve haver uma opção como allow-any-rhs
). Atualmente, não posso usar strict-boolean-expressions
, pois há muitos curto-circuitos em nosso código-base.
Verificar o LHS deve permanecer como está IMHO, uma vez que usar string
ou number
como LHS pode ser perigoso, veja este exemplo:
function foo(x: string | number | null) {
return x || defaultValue;
}
Isso é perigoso, pois muitos desenvolvedores não entenderão que não apenas null
mas também 0
e ""
farão com que defaultValue
seja devolvido.
Tive que lidar com os principais bugs em meu projeto, devido aos desenvolvedores não levarem em consideração que ""
e 0
também são falsey. Prevenir esse tipo de código é meu principal caso de uso para strict-boolean-expressions
.
Corrigido em https://github.com/palantir/tslint/pull/4159 só precisa da revisão de um colaborador.
Ops, só queria esclarecer que um dos meus exemplos era ruim:
const x = possiblyUndefined || 5;
Isso não deveria funcionar porque possiblyUndefined
pode ser 0
que pode ser um erro lógico. Parece que o RP de @dobesv funcionaria aqui.
inclui para array é um recurso ES7.
Você precisa alterar sua configuração para usar ES7 ou ESNEXT 🦄
Atenciosamente, 🚀
@rimiti Olá, não consigo entender a que você está se referindo. Tem certeza de que postou esse comentário no tópico certo?
@dobesv Oh, sinto muito;)
corrigido por # 4159, estará disponível na próxima versão
Comentários muito úteis
Na minha opinião,
strict-boolean-expressions
deve verificar apenas o operando esquerdo de&&
e||
. Esses operadores são (essencialmente) açúcar para ternários:a && b
é igual aa ? b : a
ea || b
é igual aa ? a : b
. Quando você pensa sobre isso nesses termos, ignorar o RHS faz muito sentido e colocaria o comportamento dos operadores em curto-circuito em linha com o comportamento dos ternários.Então , se tudo estiver dentro de um if / for / while,
strict-boolean-conditions
pode entrar em ação e verificar a expressão geral . Acho que isso cobriria todos os casos úteis e eu seria capaz de ativar essa regra novamente.O código que sinalizou isso como um problema para mim foi este padrão React comum documentado:
@ajafff Seu código não passa o linter para mim, mesmo com todas as opções da regra habilitadas, devido ao RHS constante:
A intenção da expressão é uma condição do LHS, portanto, minha proposta de ignorar o RHS também resolveria o problema dele.