| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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)) | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } | ||
| } |
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt turns out that the original type can be reassigned based on optionalChainContainsReference. That messed up the else branch because narrowTypeByBooleanComparison was operating on the wrong type.
I've also tried keeping originalType around and pass that to narrowTypeByBooleanComparison. That fixed the reported issue~ related to the wrong type in the else branch but it broke the same type within the if block. This happened because originally the intention was for that reassigned type to be returned through the return at the bottom of this function but I changed it to return originalType through narrowTypeByBooleanComparison.
So all in all, this seems like the simplest fix and reflects the intention the best. The motivation behind the original change was to improve non-access expression narrowing. Access expressions are already handled by discrimination-based narrowing etc.
Even though it worked previously (as far as I know) for non-optional chain access expressions, this helps them avoid some redundant work too.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis seems fine as a quick fix for now, though I suspect that we could try and do better later.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThen again, not sure what "better" even means; an expression like (options?.a === false || options.b is not the same as (!options?.a || options.b) so realistically I don't think there's any extra info gained here.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.