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);

`