feat(36048): handle uncalled function checks in ternaries (#36402)

This commit is contained in:
Alexander T 2020-02-20 19:29:41 +02:00 committed by GitHub
parent c8147cb601
commit bf6be75131
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 688 additions and 10 deletions

View file

@ -27929,7 +27929,8 @@ namespace ts {
}
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
checkTruthinessExpression(node.condition);
const type = checkTruthinessExpression(node.condition);
checkTestingKnownTruthyCallableType(node.condition, node.whenTrue, type);
const type1 = checkExpression(node.whenTrue, checkMode);
const type2 = checkExpression(node.whenFalse, checkMode);
return getUnionType([type1, type2], UnionReduction.Subtype);
@ -31051,9 +31052,8 @@ namespace ts {
function checkIfStatement(node: IfStatement) {
// Grammar checking
checkGrammarStatementInAmbientContext(node);
const type = checkTruthinessExpression(node.expression);
checkTestingKnownTruthyCallableType(node, type);
checkTestingKnownTruthyCallableType(node.expression, node.thenStatement, type);
checkSourceElement(node.thenStatement);
if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
@ -31063,15 +31063,15 @@ namespace ts {
checkSourceElement(node.elseStatement);
}
function checkTestingKnownTruthyCallableType(ifStatement: IfStatement, type: Type) {
function checkTestingKnownTruthyCallableType(condExpr: Expression, body: Statement | Expression, type: Type) {
if (!strictNullChecks) {
return;
}
const testedNode = isIdentifier(ifStatement.expression)
? ifStatement.expression
: isPropertyAccessExpression(ifStatement.expression)
? ifStatement.expression.name
const testedNode = isIdentifier(condExpr)
? condExpr
: isPropertyAccessExpression(condExpr)
? condExpr.name
: undefined;
if (!testedNode) {
@ -31098,7 +31098,7 @@ namespace ts {
return;
}
const functionIsUsedInBody = forEachChild(ifStatement.thenStatement, function check(childNode): boolean | undefined {
const functionIsUsedInBody = forEachChild(body, function check(childNode): boolean | undefined {
if (isIdentifier(childNode)) {
const childSymbol = getSymbolAtLocation(childNode);
if (childSymbol && childSymbol.id === testedFunctionSymbol.id) {
@ -31110,7 +31110,7 @@ namespace ts {
});
if (!functionIsUsedInBody) {
error(ifStatement.expression, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
error(condExpr, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
}
}

View file

@ -0,0 +1,85 @@
tests/cases/compiler/truthinessCallExpressionCoercion1.ts(3,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
tests/cases/compiler/truthinessCallExpressionCoercion1.ts(19,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
tests/cases/compiler/truthinessCallExpressionCoercion1.ts(33,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
tests/cases/compiler/truthinessCallExpressionCoercion1.ts(46,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
tests/cases/compiler/truthinessCallExpressionCoercion1.ts(61,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
==== tests/cases/compiler/truthinessCallExpressionCoercion1.ts (5 errors) ====
function onlyErrorsWhenTestingNonNullableFunctionType(required: () => boolean, optional?: () => boolean) {
// error
required ? console.log('required') : undefined;
~~~~~~~~
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
// ok
optional ? console.log('optional') : undefined;
// ok
!!required ? console.log('not required') : undefined;
// ok
required() ? console.log('required call') : undefined;
}
function onlyErrorsWhenUnusedInBody() {
function test() { return Math.random() > 0.5; }
// error
test ? console.log('test') : undefined;
~~~~
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
// ok
test ? console.log(test) : undefined;
// ok
test ? test() : undefined;
// ok
test
? [() => null].forEach(() => { test(); })
: undefined;
// error
test
~~~~
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
? [() => null].forEach(test => { test() })
: undefined;
}
function checksPropertyAccess() {
const x = {
foo: {
bar() { return true; }
}
}
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
~~~~~~~~~
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
// ok
x.foo.bar ? x.foo.bar : undefined;
}
class Foo {
maybeIsUser?: () => boolean;
isUser() {
return true;
}
test() {
// error
this.isUser ? console.log('this.isUser') : undefined;
~~~~~~~~~~~
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
}
}

View file

@ -0,0 +1,122 @@
//// [truthinessCallExpressionCoercion1.ts]
function onlyErrorsWhenTestingNonNullableFunctionType(required: () => boolean, optional?: () => boolean) {
// error
required ? console.log('required') : undefined;
// ok
optional ? console.log('optional') : undefined;
// ok
!!required ? console.log('not required') : undefined;
// ok
required() ? console.log('required call') : undefined;
}
function onlyErrorsWhenUnusedInBody() {
function test() { return Math.random() > 0.5; }
// error
test ? console.log('test') : undefined;
// ok
test ? console.log(test) : undefined;
// ok
test ? test() : undefined;
// ok
test
? [() => null].forEach(() => { test(); })
: undefined;
// error
test
? [() => null].forEach(test => { test() })
: undefined;
}
function checksPropertyAccess() {
const x = {
foo: {
bar() { return true; }
}
}
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
// ok
x.foo.bar ? x.foo.bar : undefined;
}
class Foo {
maybeIsUser?: () => boolean;
isUser() {
return true;
}
test() {
// error
this.isUser ? console.log('this.isUser') : undefined;
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
}
}
//// [truthinessCallExpressionCoercion1.js]
function onlyErrorsWhenTestingNonNullableFunctionType(required, optional) {
// error
required ? console.log('required') : undefined;
// ok
optional ? console.log('optional') : undefined;
// ok
!!required ? console.log('not required') : undefined;
// ok
required() ? console.log('required call') : undefined;
}
function onlyErrorsWhenUnusedInBody() {
function test() { return Math.random() > 0.5; }
// error
test ? console.log('test') : undefined;
// ok
test ? console.log(test) : undefined;
// ok
test ? test() : undefined;
// ok
test
? [function () { return null; }].forEach(function () { test(); })
: undefined;
// error
test
? [function () { return null; }].forEach(function (test) { test(); })
: undefined;
}
function checksPropertyAccess() {
var x = {
foo: {
bar: function () { return true; }
}
};
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
// ok
x.foo.bar ? x.foo.bar : undefined;
}
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.isUser = function () {
return true;
};
Foo.prototype.test = function () {
// error
this.isUser ? console.log('this.isUser') : undefined;
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
};
return Foo;
}());

View file

@ -0,0 +1,175 @@
=== tests/cases/compiler/truthinessCallExpressionCoercion1.ts ===
function onlyErrorsWhenTestingNonNullableFunctionType(required: () => boolean, optional?: () => boolean) {
>onlyErrorsWhenTestingNonNullableFunctionType : Symbol(onlyErrorsWhenTestingNonNullableFunctionType, Decl(truthinessCallExpressionCoercion1.ts, 0, 0))
>required : Symbol(required, Decl(truthinessCallExpressionCoercion1.ts, 0, 54))
>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion1.ts, 0, 78))
// error
required ? console.log('required') : undefined;
>required : Symbol(required, Decl(truthinessCallExpressionCoercion1.ts, 0, 54))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
optional ? console.log('optional') : undefined;
>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion1.ts, 0, 78))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
!!required ? console.log('not required') : undefined;
>required : Symbol(required, Decl(truthinessCallExpressionCoercion1.ts, 0, 54))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
required() ? console.log('required call') : undefined;
>required : Symbol(required, Decl(truthinessCallExpressionCoercion1.ts, 0, 54))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
}
function onlyErrorsWhenUnusedInBody() {
>onlyErrorsWhenUnusedInBody : Symbol(onlyErrorsWhenUnusedInBody, Decl(truthinessCallExpressionCoercion1.ts, 12, 1))
function test() { return Math.random() > 0.5; }
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
// error
test ? console.log('test') : undefined;
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
test ? console.log(test) : undefined;
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>undefined : Symbol(undefined)
// ok
test ? test() : undefined;
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
>undefined : Symbol(undefined)
// ok
test
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
? [() => null].forEach(() => { test(); })
>[() => null].forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
: undefined;
>undefined : Symbol(undefined)
// error
test
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 14, 39))
? [() => null].forEach(test => { test() })
>[() => null].forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 33, 31))
>test : Symbol(test, Decl(truthinessCallExpressionCoercion1.ts, 33, 31))
: undefined;
>undefined : Symbol(undefined)
}
function checksPropertyAccess() {
>checksPropertyAccess : Symbol(checksPropertyAccess, Decl(truthinessCallExpressionCoercion1.ts, 35, 1))
const x = {
>x : Symbol(x, Decl(truthinessCallExpressionCoercion1.ts, 38, 9))
foo: {
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
bar() { return true; }
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
}
}
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>x : Symbol(x, Decl(truthinessCallExpressionCoercion1.ts, 38, 9))
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
x.foo.bar ? x.foo.bar : undefined;
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>x : Symbol(x, Decl(truthinessCallExpressionCoercion1.ts, 38, 9))
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>x : Symbol(x, Decl(truthinessCallExpressionCoercion1.ts, 38, 9))
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15))
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14))
>undefined : Symbol(undefined)
}
class Foo {
>Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1))
maybeIsUser?: () => boolean;
>maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11))
isUser() {
>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32))
return true;
}
test() {
>test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion1.ts, 56, 5))
// error
this.isUser ? console.log('this.isUser') : undefined;
>this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32))
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1))
>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
>this.maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11))
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1))
>maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>undefined : Symbol(undefined)
}
}

View file

@ -0,0 +1,228 @@
=== tests/cases/compiler/truthinessCallExpressionCoercion1.ts ===
function onlyErrorsWhenTestingNonNullableFunctionType(required: () => boolean, optional?: () => boolean) {
>onlyErrorsWhenTestingNonNullableFunctionType : (required: () => boolean, optional?: (() => boolean) | undefined) => void
>required : () => boolean
>optional : (() => boolean) | undefined
// error
required ? console.log('required') : undefined;
>required ? console.log('required') : undefined : void
>required : () => boolean
>console.log('required') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'required' : "required"
>undefined : undefined
// ok
optional ? console.log('optional') : undefined;
>optional ? console.log('optional') : undefined : void
>optional : (() => boolean) | undefined
>console.log('optional') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'optional' : "optional"
>undefined : undefined
// ok
!!required ? console.log('not required') : undefined;
>!!required ? console.log('not required') : undefined : void
>!!required : true
>!required : false
>required : () => boolean
>console.log('not required') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'not required' : "not required"
>undefined : undefined
// ok
required() ? console.log('required call') : undefined;
>required() ? console.log('required call') : undefined : void
>required() : boolean
>required : () => boolean
>console.log('required call') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'required call' : "required call"
>undefined : undefined
}
function onlyErrorsWhenUnusedInBody() {
>onlyErrorsWhenUnusedInBody : () => void
function test() { return Math.random() > 0.5; }
>test : () => boolean
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
// error
test ? console.log('test') : undefined;
>test ? console.log('test') : undefined : void
>test : () => boolean
>console.log('test') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'test' : "test"
>undefined : undefined
// ok
test ? console.log(test) : undefined;
>test ? console.log(test) : undefined : void
>test : () => boolean
>console.log(test) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>test : () => boolean
>undefined : undefined
// ok
test ? test() : undefined;
>test ? test() : undefined : boolean | undefined
>test : () => boolean
>test() : boolean
>test : () => boolean
>undefined : undefined
// ok
test
>test ? [() => null].forEach(() => { test(); }) : undefined : void
>test : () => boolean
? [() => null].forEach(() => { test(); })
>[() => null].forEach(() => { test(); }) : void
>[() => null].forEach : (callbackfn: (value: () => null, index: number, array: (() => null)[]) => void, thisArg?: any) => void
>[() => null] : (() => null)[]
>() => null : () => null
>null : null
>forEach : (callbackfn: (value: () => null, index: number, array: (() => null)[]) => void, thisArg?: any) => void
>() => { test(); } : () => void
>test() : boolean
>test : () => boolean
: undefined;
>undefined : undefined
// error
test
>test ? [() => null].forEach(test => { test() }) : undefined : void
>test : () => boolean
? [() => null].forEach(test => { test() })
>[() => null].forEach(test => { test() }) : void
>[() => null].forEach : (callbackfn: (value: () => null, index: number, array: (() => null)[]) => void, thisArg?: any) => void
>[() => null] : (() => null)[]
>() => null : () => null
>null : null
>forEach : (callbackfn: (value: () => null, index: number, array: (() => null)[]) => void, thisArg?: any) => void
>test => { test() } : (test: () => null) => void
>test : () => null
>test() : null
>test : () => null
: undefined;
>undefined : undefined
}
function checksPropertyAccess() {
>checksPropertyAccess : () => void
const x = {
>x : { foo: { bar(): boolean; }; }
>{ foo: { bar() { return true; } } } : { foo: { bar(): boolean; }; }
foo: {
>foo : { bar(): boolean; }
>{ bar() { return true; } } : { bar(): boolean; }
bar() { return true; }
>bar : () => boolean
>true : true
}
}
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
>x.foo.bar ? console.log('x.foo.bar') : undefined : void
>x.foo.bar : () => boolean
>x.foo : { bar(): boolean; }
>x : { foo: { bar(): boolean; }; }
>foo : { bar(): boolean; }
>bar : () => boolean
>console.log('x.foo.bar') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'x.foo.bar' : "x.foo.bar"
>undefined : undefined
// ok
x.foo.bar ? x.foo.bar : undefined;
>x.foo.bar ? x.foo.bar : undefined : (() => boolean) | undefined
>x.foo.bar : () => boolean
>x.foo : { bar(): boolean; }
>x : { foo: { bar(): boolean; }; }
>foo : { bar(): boolean; }
>bar : () => boolean
>x.foo.bar : () => boolean
>x.foo : { bar(): boolean; }
>x : { foo: { bar(): boolean; }; }
>foo : { bar(): boolean; }
>bar : () => boolean
>undefined : undefined
}
class Foo {
>Foo : Foo
maybeIsUser?: () => boolean;
>maybeIsUser : (() => boolean) | undefined
isUser() {
>isUser : () => boolean
return true;
>true : true
}
test() {
>test : () => void
// error
this.isUser ? console.log('this.isUser') : undefined;
>this.isUser ? console.log('this.isUser') : undefined : void
>this.isUser : () => boolean
>this : this
>isUser : () => boolean
>console.log('this.isUser') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'this.isUser' : "this.isUser"
>undefined : undefined
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
>this.maybeIsUser ? console.log('this.maybeIsUser') : undefined : void
>this.maybeIsUser : (() => boolean) | undefined
>this : this
>maybeIsUser : (() => boolean) | undefined
>console.log('this.maybeIsUser') : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>'this.maybeIsUser' : "this.maybeIsUser"
>undefined : undefined
}
}

View file

@ -0,0 +1,68 @@
// @strictNullChecks:true
function onlyErrorsWhenTestingNonNullableFunctionType(required: () => boolean, optional?: () => boolean) {
// error
required ? console.log('required') : undefined;
// ok
optional ? console.log('optional') : undefined;
// ok
!!required ? console.log('not required') : undefined;
// ok
required() ? console.log('required call') : undefined;
}
function onlyErrorsWhenUnusedInBody() {
function test() { return Math.random() > 0.5; }
// error
test ? console.log('test') : undefined;
// ok
test ? console.log(test) : undefined;
// ok
test ? test() : undefined;
// ok
test
? [() => null].forEach(() => { test(); })
: undefined;
// error
test
? [() => null].forEach(test => { test() })
: undefined;
}
function checksPropertyAccess() {
const x = {
foo: {
bar() { return true; }
}
}
// error
x.foo.bar ? console.log('x.foo.bar') : undefined;
// ok
x.foo.bar ? x.foo.bar : undefined;
}
class Foo {
maybeIsUser?: () => boolean;
isUser() {
return true;
}
test() {
// error
this.isUser ? console.log('this.isUser') : undefined;
// ok
this.maybeIsUser ? console.log('this.maybeIsUser') : undefined;
}
}