mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fixed an issue in boolean comparison narrowing when the reference is an optional chain (#56504)
This commit is contained in:
@@ -27930,10 +27930,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (isMatchingConstructorReference(right)) {
|
||||
return narrowTypeByConstructor(type, operator, left, assumeTrue);
|
||||
}
|
||||
if (isBooleanLiteral(right)) {
|
||||
if (isBooleanLiteral(right) && !isAccessExpression(left)) {
|
||||
return narrowTypeByBooleanComparison(type, left, right, operator, assumeTrue);
|
||||
}
|
||||
if (isBooleanLiteral(left)) {
|
||||
if (isBooleanLiteral(left) && !isAccessExpression(right)) {
|
||||
return narrowTypeByBooleanComparison(type, right, left, operator, assumeTrue);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
controlFlowOptionalChain3.tsx(30,8): error TS18048: 'foo' is possibly 'undefined'.
|
||||
controlFlowOptionalChain3.tsx(36,31): error TS18048: 'options' is possibly 'undefined'.
|
||||
|
||||
|
||||
==== controlFlowOptionalChain3.tsx (2 errors) ====
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56482
|
||||
|
||||
import React from "react";
|
||||
|
||||
interface Foo {
|
||||
bar: boolean;
|
||||
}
|
||||
|
||||
function test1(foo: Foo | undefined) {
|
||||
if (foo?.bar === false) {
|
||||
foo;
|
||||
}
|
||||
foo;
|
||||
}
|
||||
|
||||
function test2(foo: Foo | undefined) {
|
||||
if (foo?.bar === false) {
|
||||
foo;
|
||||
} else {
|
||||
foo;
|
||||
}
|
||||
}
|
||||
|
||||
function Test3({ foo }: { foo: Foo | undefined }) {
|
||||
return (
|
||||
<div>
|
||||
{foo?.bar === false && "foo"}
|
||||
{foo.bar ? "true" : "false"}
|
||||
~~~
|
||||
!!! error TS18048: 'foo' is possibly 'undefined'.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function test4(options?: { a?: boolean; b?: boolean }) {
|
||||
if (options?.a === false || options.b) {
|
||||
~~~~~~~
|
||||
!!! error TS18048: 'options' is possibly 'undefined'.
|
||||
options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
//// [tests/cases/conformance/controlFlow/controlFlowOptionalChain3.tsx] ////
|
||||
|
||||
=== controlFlowOptionalChain3.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56482
|
||||
|
||||
import React from "react";
|
||||
>React : Symbol(React, Decl(controlFlowOptionalChain3.tsx, 4, 6))
|
||||
|
||||
interface Foo {
|
||||
>Foo : Symbol(Foo, Decl(controlFlowOptionalChain3.tsx, 4, 26))
|
||||
|
||||
bar: boolean;
|
||||
>bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
}
|
||||
|
||||
function test1(foo: Foo | undefined) {
|
||||
>test1 : Symbol(test1, Decl(controlFlowOptionalChain3.tsx, 8, 1))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 10, 15))
|
||||
>Foo : Symbol(Foo, Decl(controlFlowOptionalChain3.tsx, 4, 26))
|
||||
|
||||
if (foo?.bar === false) {
|
||||
>foo?.bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 10, 15))
|
||||
>bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
|
||||
foo;
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 10, 15))
|
||||
}
|
||||
foo;
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 10, 15))
|
||||
}
|
||||
|
||||
function test2(foo: Foo | undefined) {
|
||||
>test2 : Symbol(test2, Decl(controlFlowOptionalChain3.tsx, 15, 1))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 17, 15))
|
||||
>Foo : Symbol(Foo, Decl(controlFlowOptionalChain3.tsx, 4, 26))
|
||||
|
||||
if (foo?.bar === false) {
|
||||
>foo?.bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 17, 15))
|
||||
>bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
|
||||
foo;
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 17, 15))
|
||||
|
||||
} else {
|
||||
foo;
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 17, 15))
|
||||
}
|
||||
}
|
||||
|
||||
function Test3({ foo }: { foo: Foo | undefined }) {
|
||||
>Test3 : Symbol(Test3, Decl(controlFlowOptionalChain3.tsx, 23, 1))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 25, 16))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 25, 25))
|
||||
>Foo : Symbol(Foo, Decl(controlFlowOptionalChain3.tsx, 4, 26))
|
||||
|
||||
return (
|
||||
<div>
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114))
|
||||
|
||||
{foo?.bar === false && "foo"}
|
||||
>foo?.bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 25, 16))
|
||||
>bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
|
||||
{foo.bar ? "true" : "false"}
|
||||
>foo.bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
>foo : Symbol(foo, Decl(controlFlowOptionalChain3.tsx, 25, 16))
|
||||
>bar : Symbol(Foo.bar, Decl(controlFlowOptionalChain3.tsx, 6, 15))
|
||||
|
||||
</div>
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2546, 114))
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
function test4(options?: { a?: boolean; b?: boolean }) {
|
||||
>test4 : Symbol(test4, Decl(controlFlowOptionalChain3.tsx, 32, 1))
|
||||
>options : Symbol(options, Decl(controlFlowOptionalChain3.tsx, 34, 15))
|
||||
>a : Symbol(a, Decl(controlFlowOptionalChain3.tsx, 34, 26))
|
||||
>b : Symbol(b, Decl(controlFlowOptionalChain3.tsx, 34, 39))
|
||||
|
||||
if (options?.a === false || options.b) {
|
||||
>options?.a : Symbol(a, Decl(controlFlowOptionalChain3.tsx, 34, 26))
|
||||
>options : Symbol(options, Decl(controlFlowOptionalChain3.tsx, 34, 15))
|
||||
>a : Symbol(a, Decl(controlFlowOptionalChain3.tsx, 34, 26))
|
||||
>options.b : Symbol(b, Decl(controlFlowOptionalChain3.tsx, 34, 39))
|
||||
>options : Symbol(options, Decl(controlFlowOptionalChain3.tsx, 34, 15))
|
||||
>b : Symbol(b, Decl(controlFlowOptionalChain3.tsx, 34, 39))
|
||||
|
||||
options;
|
||||
>options : Symbol(options, Decl(controlFlowOptionalChain3.tsx, 34, 15))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
//// [tests/cases/conformance/controlFlow/controlFlowOptionalChain3.tsx] ////
|
||||
|
||||
=== controlFlowOptionalChain3.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56482
|
||||
|
||||
import React from "react";
|
||||
>React : typeof React
|
||||
|
||||
interface Foo {
|
||||
bar: boolean;
|
||||
>bar : boolean
|
||||
}
|
||||
|
||||
function test1(foo: Foo | undefined) {
|
||||
>test1 : (foo: Foo | undefined) => void
|
||||
>foo : Foo | undefined
|
||||
|
||||
if (foo?.bar === false) {
|
||||
>foo?.bar === false : boolean
|
||||
>foo?.bar : boolean | undefined
|
||||
>foo : Foo | undefined
|
||||
>bar : boolean | undefined
|
||||
>false : false
|
||||
|
||||
foo;
|
||||
>foo : Foo
|
||||
}
|
||||
foo;
|
||||
>foo : Foo | undefined
|
||||
}
|
||||
|
||||
function test2(foo: Foo | undefined) {
|
||||
>test2 : (foo: Foo | undefined) => void
|
||||
>foo : Foo | undefined
|
||||
|
||||
if (foo?.bar === false) {
|
||||
>foo?.bar === false : boolean
|
||||
>foo?.bar : boolean | undefined
|
||||
>foo : Foo | undefined
|
||||
>bar : boolean | undefined
|
||||
>false : false
|
||||
|
||||
foo;
|
||||
>foo : Foo
|
||||
|
||||
} else {
|
||||
foo;
|
||||
>foo : Foo | undefined
|
||||
}
|
||||
}
|
||||
|
||||
function Test3({ foo }: { foo: Foo | undefined }) {
|
||||
>Test3 : ({ foo }: { foo: Foo | undefined; }) => JSX.Element
|
||||
>foo : Foo | undefined
|
||||
>foo : Foo | undefined
|
||||
|
||||
return (
|
||||
>( <div> {foo?.bar === false && "foo"} {foo.bar ? "true" : "false"} </div> ) : JSX.Element
|
||||
|
||||
<div>
|
||||
><div> {foo?.bar === false && "foo"} {foo.bar ? "true" : "false"} </div> : JSX.Element
|
||||
>div : any
|
||||
|
||||
{foo?.bar === false && "foo"}
|
||||
>foo?.bar === false && "foo" : false | "foo"
|
||||
>foo?.bar === false : boolean
|
||||
>foo?.bar : boolean | undefined
|
||||
>foo : Foo | undefined
|
||||
>bar : boolean | undefined
|
||||
>false : false
|
||||
>"foo" : "foo"
|
||||
|
||||
{foo.bar ? "true" : "false"}
|
||||
>foo.bar ? "true" : "false" : "false" | "true"
|
||||
>foo.bar : boolean
|
||||
>foo : Foo | undefined
|
||||
>bar : boolean
|
||||
>"true" : "true"
|
||||
>"false" : "false"
|
||||
|
||||
</div>
|
||||
>div : any
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
function test4(options?: { a?: boolean; b?: boolean }) {
|
||||
>test4 : (options?: { a?: boolean; b?: boolean;}) => void
|
||||
>options : { a?: boolean | undefined; b?: boolean | undefined; } | undefined
|
||||
>a : boolean | undefined
|
||||
>b : boolean | undefined
|
||||
|
||||
if (options?.a === false || options.b) {
|
||||
>options?.a === false || options.b : boolean | undefined
|
||||
>options?.a === false : boolean
|
||||
>options?.a : boolean | undefined
|
||||
>options : { a?: boolean | undefined; b?: boolean | undefined; } | undefined
|
||||
>a : boolean | undefined
|
||||
>false : false
|
||||
>options.b : boolean | undefined
|
||||
>options : { a?: boolean | undefined; b?: boolean | undefined; } | undefined
|
||||
>b : boolean | undefined
|
||||
|
||||
options;
|
||||
>options : { a?: boolean | undefined; b?: boolean | undefined; } | undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
// @esModuleInterop: true
|
||||
// @jsx: react
|
||||
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56482
|
||||
|
||||
import React from "react";
|
||||
|
||||
interface Foo {
|
||||
bar: boolean;
|
||||
}
|
||||
|
||||
function test1(foo: Foo | undefined) {
|
||||
if (foo?.bar === false) {
|
||||
foo;
|
||||
}
|
||||
foo;
|
||||
}
|
||||
|
||||
function test2(foo: Foo | undefined) {
|
||||
if (foo?.bar === false) {
|
||||
foo;
|
||||
} else {
|
||||
foo;
|
||||
}
|
||||
}
|
||||
|
||||
function Test3({ foo }: { foo: Foo | undefined }) {
|
||||
return (
|
||||
<div>
|
||||
{foo?.bar === false && "foo"}
|
||||
{foo.bar ? "true" : "false"}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function test4(options?: { a?: boolean; b?: boolean }) {
|
||||
if (options?.a === false || options.b) {
|
||||
options;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user