Only error when testing functions that return booleans · microsoft/TypeScript@327ff39 (original) (raw)
`@@ -27875,24 +27875,7 @@ namespace ts {
`
27875
27875
` checkGrammarStatementInAmbientContext(node);
`
27876
27876
``
27877
27877
` const type = checkTruthinessExpression(node.expression);
`
27878
``
-
27879
``
`-
if (strictNullChecks &&
`
27880
``
`-
(node.expression.kind === SyntaxKind.Identifier ||
`
27881
``
`-
node.expression.kind === SyntaxKind.PropertyAccessExpression ||
`
27882
``
`-
node.expression.kind === SyntaxKind.ElementAccessExpression)) {
`
27883
``
`-
const possiblyFalsy = !!getFalsyFlags(type);
`
27884
``
`-
if (!possiblyFalsy) {
`
27885
``
`-
// While it technically should be invalid for any known-truthy value
`
27886
``
`-
// to be tested, we de-scope to functions as a heuristic to identify
`
27887
``
`-
// the most common bugs. There are too many false positives for values
`
27888
``
`-
// sourced from type definitions without strictNullChecks otherwise.
`
27889
``
`-
const callSignatures = getSignaturesOfType(type, SignatureKind.Call);
`
27890
``
`-
if (callSignatures.length > 0) {
`
27891
``
`-
error(node.expression, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
`
27892
``
`-
}
`
27893
``
`-
}
`
27894
``
`-
}
`
27895
``
-
``
27878
`+
checkTestingKnownTruthyCallableType(node.expression, type);
`
27896
27879
` checkSourceElement(node.thenStatement);
`
27897
27880
``
27898
27881
` if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
`
`@@ -27902,6 +27885,59 @@ namespace ts {
`
27902
27885
` checkSourceElement(node.elseStatement);
`
27903
27886
` }
`
27904
27887
``
``
27888
`+
function checkTestingKnownTruthyCallableType(testedNode: Expression, type: Type) {
`
``
27889
`+
if (!strictNullChecks) {
`
``
27890
`+
return;
`
``
27891
`+
}
`
``
27892
+
``
27893
`+
if (testedNode.kind === SyntaxKind.Identifier ||
`
``
27894
`+
testedNode.kind === SyntaxKind.PropertyAccessExpression ||
`
``
27895
`+
testedNode.kind === SyntaxKind.ElementAccessExpression) {
`
``
27896
`+
const possiblyFalsy = getFalsyFlags(type);
`
``
27897
`+
if (possiblyFalsy) {
`
``
27898
`+
return;
`
``
27899
`+
}
`
``
27900
+
``
27901
`+
// While it technically should be invalid for any known-truthy value
`
``
27902
`+
// to be tested, we de-scope to functions that return a boolean as a
`
``
27903
`+
// heuristic to identify the most common bugs. There are too many
`
``
27904
`+
// false positives for values sourced from type definitions without
`
``
27905
`+
// strictNullChecks otherwise.
`
``
27906
`+
const callSignatures = getSignaturesOfType(type, SignatureKind.Call);
`
``
27907
`+
if (callSignatures.length === 0) {
`
``
27908
`+
return;
`
``
27909
`+
}
`
``
27910
+
``
27911
`+
const alwaysReturnsBoolean = every(callSignatures, signature => {
`
``
27912
`+
const returnType = getReturnTypeOfSignature(signature);
`
``
27913
`+
const exactlyBoolean = TypeFlags.Boolean | TypeFlags.Union;
`
``
27914
`+
if (returnType.flags === exactlyBoolean) {
`
``
27915
`+
return true;
`
``
27916
`+
}
`
``
27917
+
``
27918
`+
if (returnType.flags & TypeFlags.Union) {
`
``
27919
`+
const allowedInUnion = TypeFlags.BooleanLike | TypeFlags.Nullable;
`
``
27920
`+
let unionContainsBoolean = false;
`
``
27921
`+
const unionContainsOnlyAllowedTypes = every((returnType as UnionType).types, innerType => {
`
``
27922
`+
if (innerType.flags & TypeFlags.BooleanLike) {
`
``
27923
`+
unionContainsBoolean = true;
`
``
27924
`+
}
`
``
27925
+
``
27926
`+
return (innerType.flags | allowedInUnion) === allowedInUnion;
`
``
27927
`+
});
`
``
27928
+
``
27929
`+
return unionContainsBoolean && unionContainsOnlyAllowedTypes;
`
``
27930
`+
}
`
``
27931
+
``
27932
`+
return false;
`
``
27933
`+
});
`
``
27934
+
``
27935
`+
if (alwaysReturnsBoolean) {
`
``
27936
`+
error(testedNode, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
`
``
27937
`+
}
`
``
27938
`+
}
`
``
27939
`+
}
`
``
27940
+
27905
27941
` function checkDoStatement(node: DoStatement) {
`
27906
27942
` // Grammar checking
`
27907
27943
` checkGrammarStatementInAmbientContext(node);
`