diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb54522e57f..b1f516dad69 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19777,13 +19777,22 @@ namespace ts { } function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { - // We are in a branch of obj?.foo === value or obj?.foo !== value. We remove undefined and null from - // the type of obj if (a) the operator is === and the type of value doesn't include undefined or (b) the - // operator is !== and the type of value is undefined. - const effectiveTrue = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken ? assumeTrue : !assumeTrue; - const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; - const valueNonNullish = !(getTypeFacts(getTypeOfExpression(value)) & (doubleEquals ? TypeFacts.EQUndefinedOrNull : TypeFacts.EQUndefined)); - return effectiveTrue === valueNonNullish ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: + // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. + // When operator is !== and type of value excludes undefined, null and undefined is removed from type of obj in false branch. + // When operator is == and type of value excludes null and undefined, null and undefined is removed from type of obj in true branch. + // When operator is != and type of value excludes null and undefined, null and undefined is removed from type of obj in false branch. + // When operator is === and type of value is undefined, null and undefined is removed from type of obj in false branch. + // When operator is !== and type of value is undefined, null and undefined is removed from type of obj in true branch. + // When operator is == and type of value is null or undefined, null and undefined is removed from type of obj in false branch. + // When operator is != and type of value is null or undefined, null and undefined is removed from type of obj in true branch. + const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; + const nullableFlags = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? TypeFlags.Nullable : TypeFlags.Undefined; + const valueType = getTypeOfExpression(value); + // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. + const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || + equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); + return removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { diff --git a/tests/baselines/reference/controlFlowOptionalChain.errors.txt b/tests/baselines/reference/controlFlowOptionalChain.errors.txt index ee77494d1c8..3606034699b 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.errors.txt +++ b/tests/baselines/reference/controlFlowOptionalChain.errors.txt @@ -36,24 +36,33 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(310,9): error TS tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(319,9): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(322,9): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(331,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(334,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(337,9): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(340,9): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(343,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(346,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(349,9): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(352,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(391,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(394,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(403,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(406,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(415,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(424,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(427,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(436,9): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(471,13): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(474,13): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(488,13): error TS2532: Object is possibly 'undefined'. -tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(491,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(358,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(367,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(370,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(379,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(418,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(421,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(430,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(433,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(442,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(451,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(454,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(463,9): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(498,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(501,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(515,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(518,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(567,21): error TS2532: Object is possibly 'undefined'. -==== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts (53 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts (62 errors) ==== // assignments in shortcutting chain declare const o: undefined | { [key: string]: any; @@ -456,6 +465,49 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(491,13): error T } } + function f15a(o: Thing | undefined, value: unknown) { + if (o?.foo === value) { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + else { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + if (o?.foo !== value) { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + else { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + if (o?.foo == value) { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + else { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + if (o?.foo != value) { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + else { + o.foo; // Error + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + } + function f16(o: Thing | undefined) { if (o?.foo === undefined) { o.foo; // Error @@ -687,4 +739,29 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(491,13): error T } return f.geometry.coordinates; } + + // Repro from #35842 + + interface SomeObject { + someProperty: unknown; + } + + let lastSomeProperty: unknown | undefined; + + function someFunction(someOptionalObject: SomeObject | undefined): void { + if (someOptionalObject?.someProperty !== lastSomeProperty) { + console.log(someOptionalObject); + console.log(someOptionalObject.someProperty); // Error + ~~~~~~~~~~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + lastSomeProperty = someOptionalObject?.someProperty; + } + } + + const someObject: SomeObject = { + someProperty: 42 + }; + + someFunction(someObject); + someFunction(undefined); \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowOptionalChain.js b/tests/baselines/reference/controlFlowOptionalChain.js index a3ab92334a9..cd7b9a92377 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.js +++ b/tests/baselines/reference/controlFlowOptionalChain.js @@ -327,6 +327,33 @@ function f15(o: Thing | undefined, value: number) { } } +function f15a(o: Thing | undefined, value: unknown) { + if (o?.foo === value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo !== value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo == value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo != value) { + o.foo; // Error + } + else { + o.foo; // Error + } +} + function f16(o: Thing | undefined) { if (o?.foo === undefined) { o.foo; // Error @@ -526,6 +553,29 @@ function extractCoordinates(f: Feature): number[] { } return f.geometry.coordinates; } + +// Repro from #35842 + +interface SomeObject { + someProperty: unknown; +} + +let lastSomeProperty: unknown | undefined; + +function someFunction(someOptionalObject: SomeObject | undefined): void { + if (someOptionalObject?.someProperty !== lastSomeProperty) { + console.log(someOptionalObject); + console.log(someOptionalObject.someProperty); // Error + lastSomeProperty = someOptionalObject?.someProperty; + } +} + +const someObject: SomeObject = { + someProperty: 42 +}; + +someFunction(someObject); +someFunction(undefined); //// [controlFlowOptionalChain.js] @@ -809,6 +859,32 @@ function f15(o, value) { o.foo; } } +function f15a(o, value) { + if ((o === null || o === void 0 ? void 0 : o.foo) === value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if ((o === null || o === void 0 ? void 0 : o.foo) !== value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if ((o === null || o === void 0 ? void 0 : o.foo) == value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if ((o === null || o === void 0 ? void 0 : o.foo) != value) { + o.foo; // Error + } + else { + o.foo; // Error + } +} function f16(o) { if ((o === null || o === void 0 ? void 0 : o.foo) === undefined) { o.foo; // Error @@ -982,3 +1058,16 @@ function extractCoordinates(f) { } return f.geometry.coordinates; } +var lastSomeProperty; +function someFunction(someOptionalObject) { + if ((someOptionalObject === null || someOptionalObject === void 0 ? void 0 : someOptionalObject.someProperty) !== lastSomeProperty) { + console.log(someOptionalObject); + console.log(someOptionalObject.someProperty); // Error + lastSomeProperty = someOptionalObject === null || someOptionalObject === void 0 ? void 0 : someOptionalObject.someProperty; + } +} +var someObject = { + someProperty: 42 +}; +someFunction(someObject); +someFunction(undefined); diff --git a/tests/baselines/reference/controlFlowOptionalChain.symbols b/tests/baselines/reference/controlFlowOptionalChain.symbols index cac0899cc89..42c32487f6e 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.symbols +++ b/tests/baselines/reference/controlFlowOptionalChain.symbols @@ -1115,403 +1115,479 @@ function f15(o: Thing | undefined, value: number) { } } +function f15a(o: Thing | undefined, value: unknown) { +>f15a : Symbol(f15a, Decl(controlFlowOptionalChain.ts, 326, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) +>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 328, 35)) + + if (o?.foo === value) { +>o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 328, 35)) + + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + else { + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + if (o?.foo !== value) { +>o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 328, 35)) + + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + else { + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + if (o?.foo == value) { +>o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 328, 35)) + + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + else { + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + if (o?.foo != value) { +>o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 328, 35)) + + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } + else { + o.foo; // Error +>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 14)) +>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) + } +} + function f16(o: Thing | undefined) { ->f16 : Symbol(f16, Decl(controlFlowOptionalChain.ts, 326, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>f16 : Symbol(f16, Decl(controlFlowOptionalChain.ts, 353, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (o?.foo === undefined) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) >undefined : Symbol(undefined) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (o?.foo !== undefined) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) >undefined : Symbol(undefined) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (o?.foo == undefined) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) >undefined : Symbol(undefined) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (o?.foo != undefined) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) >undefined : Symbol(undefined) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 328, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } } function f20(o: Thing | undefined) { ->f20 : Symbol(f20, Decl(controlFlowOptionalChain.ts, 353, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>f20 : Symbol(f20, Decl(controlFlowOptionalChain.ts, 380, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (typeof o?.foo === "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.["foo"] === "number") { ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) o["foo"]; ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >"foo" : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.bar() === "number") { >o?.bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) o.bar; >o.bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) } if (o?.baz instanceof Error) { >o?.baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) >Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) o.baz; >o.baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 355, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 382, 13)) >baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) } } function f21(o: Thing | null) { ->f21 : Symbol(f21, Decl(controlFlowOptionalChain.ts, 368, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>f21 : Symbol(f21, Decl(controlFlowOptionalChain.ts, 395, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (typeof o?.foo === "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.["foo"] === "number") { ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) o["foo"]; ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >"foo" : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.bar() === "number") { >o?.bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) o.bar; >o.bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >bar : Symbol(bar, Decl(controlFlowOptionalChain.ts, 161, 36)) } if (o?.baz instanceof Error) { >o?.baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) >Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) o.baz; >o.baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 370, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 397, 13)) >baz : Symbol(baz, Decl(controlFlowOptionalChain.ts, 161, 51)) } } function f22(o: Thing | undefined) { ->f22 : Symbol(f22, Decl(controlFlowOptionalChain.ts, 383, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>f22 : Symbol(f22, Decl(controlFlowOptionalChain.ts, 410, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (typeof o?.foo === "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo !== "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo == "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo != "number") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 385, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } } function f23(o: Thing | undefined) { ->f23 : Symbol(f23, Decl(controlFlowOptionalChain.ts, 410, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>f23 : Symbol(f23, Decl(controlFlowOptionalChain.ts, 437, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (typeof o?.foo === "undefined") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo !== "undefined") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo == "undefined") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (typeof o?.foo != "undefined") { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } else { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 412, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } } declare function assert(x: unknown): asserts x; ->assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 437, 1)) ->x : Symbol(x, Decl(controlFlowOptionalChain.ts, 439, 24)) ->x : Symbol(x, Decl(controlFlowOptionalChain.ts, 439, 24)) +>assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 464, 1)) +>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 466, 24)) +>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 466, 24)) declare function assertNonNull(x: T): asserts x is NonNullable; ->assertNonNull : Symbol(assertNonNull, Decl(controlFlowOptionalChain.ts, 439, 47)) ->T : Symbol(T, Decl(controlFlowOptionalChain.ts, 440, 31)) ->x : Symbol(x, Decl(controlFlowOptionalChain.ts, 440, 34)) ->T : Symbol(T, Decl(controlFlowOptionalChain.ts, 440, 31)) ->x : Symbol(x, Decl(controlFlowOptionalChain.ts, 440, 34)) +>assertNonNull : Symbol(assertNonNull, Decl(controlFlowOptionalChain.ts, 466, 47)) +>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 467, 31)) +>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 467, 34)) +>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 467, 31)) +>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 467, 34)) >NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(controlFlowOptionalChain.ts, 440, 31)) +>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 467, 31)) function f30(o: Thing | undefined) { ->f30 : Symbol(f30, Decl(controlFlowOptionalChain.ts, 440, 69)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>f30 : Symbol(f30, Decl(controlFlowOptionalChain.ts, 467, 69)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) if (!!true) { assert(o?.foo); ->assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 437, 1)) +>assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 464, 1)) >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (!!true) { assert(o?.foo === 42); ->assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 437, 1)) +>assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 464, 1)) >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (!!true) { assert(typeof o?.foo === "number"); ->assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 437, 1)) +>assert : Symbol(assert, Decl(controlFlowOptionalChain.ts, 464, 1)) >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } if (!!true) { assertNonNull(o?.foo); ->assertNonNull : Symbol(assertNonNull, Decl(controlFlowOptionalChain.ts, 439, 47)) +>assertNonNull : Symbol(assertNonNull, Decl(controlFlowOptionalChain.ts, 466, 47)) >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 442, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 469, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) } } function f40(o: Thing | undefined) { ->f40 : Symbol(f40, Decl(controlFlowOptionalChain.ts, 459, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>f40 : Symbol(f40, Decl(controlFlowOptionalChain.ts, 486, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) switch (o?.foo) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) case "abc": o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; case 42: o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; @@ -1520,14 +1596,14 @@ function f40(o: Thing | undefined) { o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; default: o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 461, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 488, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; @@ -1535,40 +1611,40 @@ function f40(o: Thing | undefined) { } function f41(o: Thing | undefined) { ->f41 : Symbol(f41, Decl(controlFlowOptionalChain.ts, 476, 1)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>f41 : Symbol(f41, Decl(controlFlowOptionalChain.ts, 503, 1)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >Thing : Symbol(Thing, Decl(controlFlowOptionalChain.ts, 159, 1)) switch (typeof o?.foo) { >o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) case "string": o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; case "number": o.foo; >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; case "undefined": o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; default: o.foo; // Error >o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) ->o : Symbol(o, Decl(controlFlowOptionalChain.ts, 478, 13)) +>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13)) >foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14)) break; @@ -1578,44 +1654,44 @@ function f41(o: Thing | undefined) { // Repros from #34570 type Shape = ->Shape : Symbol(Shape, Decl(controlFlowOptionalChain.ts, 493, 1)) +>Shape : Symbol(Shape, Decl(controlFlowOptionalChain.ts, 520, 1)) | { type: 'rectangle', width: number, height: number } ->type : Symbol(type, Decl(controlFlowOptionalChain.ts, 498, 7)) ->width : Symbol(width, Decl(controlFlowOptionalChain.ts, 498, 26)) ->height : Symbol(height, Decl(controlFlowOptionalChain.ts, 498, 41)) +>type : Symbol(type, Decl(controlFlowOptionalChain.ts, 525, 7)) +>width : Symbol(width, Decl(controlFlowOptionalChain.ts, 525, 26)) +>height : Symbol(height, Decl(controlFlowOptionalChain.ts, 525, 41)) | { type: 'circle', radius: number } ->type : Symbol(type, Decl(controlFlowOptionalChain.ts, 499, 7)) ->radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 499, 23)) +>type : Symbol(type, Decl(controlFlowOptionalChain.ts, 526, 7)) +>radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 526, 23)) function getArea(shape?: Shape) { ->getArea : Symbol(getArea, Decl(controlFlowOptionalChain.ts, 499, 40)) ->shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 501, 17)) ->Shape : Symbol(Shape, Decl(controlFlowOptionalChain.ts, 493, 1)) +>getArea : Symbol(getArea, Decl(controlFlowOptionalChain.ts, 526, 40)) +>shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 528, 17)) +>Shape : Symbol(Shape, Decl(controlFlowOptionalChain.ts, 520, 1)) switch (shape?.type) { ->shape?.type : Symbol(type, Decl(controlFlowOptionalChain.ts, 498, 7), Decl(controlFlowOptionalChain.ts, 499, 7)) ->shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 501, 17)) ->type : Symbol(type, Decl(controlFlowOptionalChain.ts, 498, 7), Decl(controlFlowOptionalChain.ts, 499, 7)) +>shape?.type : Symbol(type, Decl(controlFlowOptionalChain.ts, 525, 7), Decl(controlFlowOptionalChain.ts, 526, 7)) +>shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 528, 17)) +>type : Symbol(type, Decl(controlFlowOptionalChain.ts, 525, 7), Decl(controlFlowOptionalChain.ts, 526, 7)) case 'circle': return Math.PI * shape.radius ** 2 >Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) >Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --)) ->shape.radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 499, 23)) ->shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 501, 17)) ->radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 499, 23)) +>shape.radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 526, 23)) +>shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 528, 17)) +>radius : Symbol(radius, Decl(controlFlowOptionalChain.ts, 526, 23)) case 'rectangle': return shape.width * shape.height ->shape.width : Symbol(width, Decl(controlFlowOptionalChain.ts, 498, 26)) ->shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 501, 17)) ->width : Symbol(width, Decl(controlFlowOptionalChain.ts, 498, 26)) ->shape.height : Symbol(height, Decl(controlFlowOptionalChain.ts, 498, 41)) ->shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 501, 17)) ->height : Symbol(height, Decl(controlFlowOptionalChain.ts, 498, 41)) +>shape.width : Symbol(width, Decl(controlFlowOptionalChain.ts, 525, 26)) +>shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 528, 17)) +>width : Symbol(width, Decl(controlFlowOptionalChain.ts, 525, 26)) +>shape.height : Symbol(height, Decl(controlFlowOptionalChain.ts, 525, 41)) +>shape : Symbol(shape, Decl(controlFlowOptionalChain.ts, 528, 17)) +>height : Symbol(height, Decl(controlFlowOptionalChain.ts, 525, 41)) default: return 0 @@ -1623,43 +1699,105 @@ function getArea(shape?: Shape) { } type Feature = { ->Feature : Symbol(Feature, Decl(controlFlowOptionalChain.ts, 510, 1)) +>Feature : Symbol(Feature, Decl(controlFlowOptionalChain.ts, 537, 1)) id: string; ->id : Symbol(id, Decl(controlFlowOptionalChain.ts, 512, 16)) +>id : Symbol(id, Decl(controlFlowOptionalChain.ts, 539, 16)) geometry?: { ->geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 513, 13)) +>geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 540, 13)) type: string; ->type : Symbol(type, Decl(controlFlowOptionalChain.ts, 514, 14)) +>type : Symbol(type, Decl(controlFlowOptionalChain.ts, 541, 14)) coordinates: number[]; ->coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 515, 17)) +>coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 542, 17)) }; }; function extractCoordinates(f: Feature): number[] { ->extractCoordinates : Symbol(extractCoordinates, Decl(controlFlowOptionalChain.ts, 518, 2)) ->f : Symbol(f, Decl(controlFlowOptionalChain.ts, 521, 28)) ->Feature : Symbol(Feature, Decl(controlFlowOptionalChain.ts, 510, 1)) +>extractCoordinates : Symbol(extractCoordinates, Decl(controlFlowOptionalChain.ts, 545, 2)) +>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 548, 28)) +>Feature : Symbol(Feature, Decl(controlFlowOptionalChain.ts, 537, 1)) if (f.geometry?.type !== 'test') { ->f.geometry?.type : Symbol(type, Decl(controlFlowOptionalChain.ts, 514, 14)) ->f.geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 513, 13)) ->f : Symbol(f, Decl(controlFlowOptionalChain.ts, 521, 28)) ->geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 513, 13)) ->type : Symbol(type, Decl(controlFlowOptionalChain.ts, 514, 14)) +>f.geometry?.type : Symbol(type, Decl(controlFlowOptionalChain.ts, 541, 14)) +>f.geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 540, 13)) +>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 548, 28)) +>geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 540, 13)) +>type : Symbol(type, Decl(controlFlowOptionalChain.ts, 541, 14)) return []; } return f.geometry.coordinates; ->f.geometry.coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 515, 17)) ->f.geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 513, 13)) ->f : Symbol(f, Decl(controlFlowOptionalChain.ts, 521, 28)) ->geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 513, 13)) ->coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 515, 17)) +>f.geometry.coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 542, 17)) +>f.geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 540, 13)) +>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 548, 28)) +>geometry : Symbol(geometry, Decl(controlFlowOptionalChain.ts, 540, 13)) +>coordinates : Symbol(coordinates, Decl(controlFlowOptionalChain.ts, 542, 17)) } +// Repro from #35842 + +interface SomeObject { +>SomeObject : Symbol(SomeObject, Decl(controlFlowOptionalChain.ts, 553, 1)) + + someProperty: unknown; +>someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) +} + +let lastSomeProperty: unknown | undefined; +>lastSomeProperty : Symbol(lastSomeProperty, Decl(controlFlowOptionalChain.ts, 561, 3)) + +function someFunction(someOptionalObject: SomeObject | undefined): void { +>someFunction : Symbol(someFunction, Decl(controlFlowOptionalChain.ts, 561, 42)) +>someOptionalObject : Symbol(someOptionalObject, Decl(controlFlowOptionalChain.ts, 563, 22)) +>SomeObject : Symbol(SomeObject, Decl(controlFlowOptionalChain.ts, 553, 1)) + + if (someOptionalObject?.someProperty !== lastSomeProperty) { +>someOptionalObject?.someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) +>someOptionalObject : Symbol(someOptionalObject, Decl(controlFlowOptionalChain.ts, 563, 22)) +>someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) +>lastSomeProperty : Symbol(lastSomeProperty, Decl(controlFlowOptionalChain.ts, 561, 3)) + + console.log(someOptionalObject); +>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, --, --)) +>someOptionalObject : Symbol(someOptionalObject, Decl(controlFlowOptionalChain.ts, 563, 22)) + + console.log(someOptionalObject.someProperty); // Error +>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, --, --)) +>someOptionalObject.someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) +>someOptionalObject : Symbol(someOptionalObject, Decl(controlFlowOptionalChain.ts, 563, 22)) +>someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) + + lastSomeProperty = someOptionalObject?.someProperty; +>lastSomeProperty : Symbol(lastSomeProperty, Decl(controlFlowOptionalChain.ts, 561, 3)) +>someOptionalObject?.someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) +>someOptionalObject : Symbol(someOptionalObject, Decl(controlFlowOptionalChain.ts, 563, 22)) +>someProperty : Symbol(SomeObject.someProperty, Decl(controlFlowOptionalChain.ts, 557, 22)) + } +} + +const someObject: SomeObject = { +>someObject : Symbol(someObject, Decl(controlFlowOptionalChain.ts, 571, 5)) +>SomeObject : Symbol(SomeObject, Decl(controlFlowOptionalChain.ts, 553, 1)) + + someProperty: 42 +>someProperty : Symbol(someProperty, Decl(controlFlowOptionalChain.ts, 571, 32)) + +}; + +someFunction(someObject); +>someFunction : Symbol(someFunction, Decl(controlFlowOptionalChain.ts, 561, 42)) +>someObject : Symbol(someObject, Decl(controlFlowOptionalChain.ts, 571, 5)) + +someFunction(undefined); +>someFunction : Symbol(someFunction, Decl(controlFlowOptionalChain.ts, 561, 42)) +>undefined : Symbol(undefined) + diff --git a/tests/baselines/reference/controlFlowOptionalChain.types b/tests/baselines/reference/controlFlowOptionalChain.types index 13dd6cd5fd0..37a688ca25c 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.types +++ b/tests/baselines/reference/controlFlowOptionalChain.types @@ -1249,6 +1249,85 @@ function f15(o: Thing | undefined, value: number) { } } +function f15a(o: Thing | undefined, value: unknown) { +>f15a : (o: Thing | undefined, value: unknown) => void +>o : Thing | undefined +>value : unknown + + if (o?.foo === value) { +>o?.foo === value : boolean +>o?.foo : string | number | undefined +>o : Thing | undefined +>foo : string | number | undefined +>value : unknown + + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + else { + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + if (o?.foo !== value) { +>o?.foo !== value : boolean +>o?.foo : string | number | undefined +>o : Thing | undefined +>foo : string | number | undefined +>value : unknown + + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + else { + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + if (o?.foo == value) { +>o?.foo == value : boolean +>o?.foo : string | number | undefined +>o : Thing | undefined +>foo : string | number | undefined +>value : unknown + + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + else { + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + if (o?.foo != value) { +>o?.foo != value : boolean +>o?.foo : string | number | undefined +>o : Thing | undefined +>foo : string | number | undefined +>value : unknown + + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } + else { + o.foo; // Error +>o.foo : string | number +>o : Thing | undefined +>foo : string | number + } +} + function f16(o: Thing | undefined) { >f16 : (o: Thing | undefined) => void >o : Thing | undefined @@ -1886,3 +1965,69 @@ function extractCoordinates(f: Feature): number[] { >coordinates : number[] } +// Repro from #35842 + +interface SomeObject { + someProperty: unknown; +>someProperty : unknown +} + +let lastSomeProperty: unknown | undefined; +>lastSomeProperty : unknown + +function someFunction(someOptionalObject: SomeObject | undefined): void { +>someFunction : (someOptionalObject: SomeObject | undefined) => void +>someOptionalObject : SomeObject | undefined + + if (someOptionalObject?.someProperty !== lastSomeProperty) { +>someOptionalObject?.someProperty !== lastSomeProperty : boolean +>someOptionalObject?.someProperty : unknown +>someOptionalObject : SomeObject | undefined +>someProperty : unknown +>lastSomeProperty : unknown + + console.log(someOptionalObject); +>console.log(someOptionalObject) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>someOptionalObject : SomeObject | undefined + + console.log(someOptionalObject.someProperty); // Error +>console.log(someOptionalObject.someProperty) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>someOptionalObject.someProperty : unknown +>someOptionalObject : SomeObject | undefined +>someProperty : unknown + + lastSomeProperty = someOptionalObject?.someProperty; +>lastSomeProperty = someOptionalObject?.someProperty : unknown +>lastSomeProperty : unknown +>someOptionalObject?.someProperty : unknown +>someOptionalObject : SomeObject | undefined +>someProperty : unknown + } +} + +const someObject: SomeObject = { +>someObject : SomeObject +>{ someProperty: 42} : { someProperty: number; } + + someProperty: 42 +>someProperty : number +>42 : 42 + +}; + +someFunction(someObject); +>someFunction(someObject) : void +>someFunction : (someOptionalObject: SomeObject | undefined) => void +>someObject : SomeObject + +someFunction(undefined); +>someFunction(undefined) : void +>someFunction : (someOptionalObject: SomeObject | undefined) => void +>undefined : undefined + diff --git a/tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts b/tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts index 49ebd3807db..443716ef8c3 100644 --- a/tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts +++ b/tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts @@ -329,6 +329,33 @@ function f15(o: Thing | undefined, value: number) { } } +function f15a(o: Thing | undefined, value: unknown) { + if (o?.foo === value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo !== value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo == value) { + o.foo; // Error + } + else { + o.foo; // Error + } + if (o?.foo != value) { + o.foo; // Error + } + else { + o.foo; // Error + } +} + function f16(o: Thing | undefined) { if (o?.foo === undefined) { o.foo; // Error @@ -528,3 +555,26 @@ function extractCoordinates(f: Feature): number[] { } return f.geometry.coordinates; } + +// Repro from #35842 + +interface SomeObject { + someProperty: unknown; +} + +let lastSomeProperty: unknown | undefined; + +function someFunction(someOptionalObject: SomeObject | undefined): void { + if (someOptionalObject?.someProperty !== lastSomeProperty) { + console.log(someOptionalObject); + console.log(someOptionalObject.someProperty); // Error + lastSomeProperty = someOptionalObject?.someProperty; + } +} + +const someObject: SomeObject = { + someProperty: 42 +}; + +someFunction(someObject); +someFunction(undefined);