From d2be8900dc8feff8eeed84e4168d4f3d83955f47 Mon Sep 17 00:00:00 2001 From: kingwl Date: Wed, 8 Apr 2020 12:09:56 +0800 Subject: [PATCH] Add type narrow --- src/compiler/binder.ts | 3 + src/compiler/checker.ts | 4 + ...gicalAssignment4(target=es2015).errors.txt | 36 ++++++-- .../logicalAssignment4(target=es2015).js | 53 ++++++++++-- .../logicalAssignment4(target=es2015).symbols | 80 ++++++++++++++--- .../logicalAssignment4(target=es2015).types | 85 ++++++++++++++++--- ...gicalAssignment4(target=es2020).errors.txt | 36 ++++++-- .../logicalAssignment4(target=es2020).js | 53 ++++++++++-- .../logicalAssignment4(target=es2020).symbols | 80 ++++++++++++++--- .../logicalAssignment4(target=es2020).types | 85 ++++++++++++++++--- ...gicalAssignment4(target=esnext).errors.txt | 36 ++++++-- .../logicalAssignment4(target=esnext).js | 53 ++++++++++-- .../logicalAssignment4(target=esnext).symbols | 80 ++++++++++++++--- .../logicalAssignment4(target=esnext).types | 85 ++++++++++++++++--- .../logicalAssignment/logicalAssignment4.ts | 27 +++++- 15 files changed, 694 insertions(+), 102 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 7cf4234b415..958129b3b1c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -905,6 +905,9 @@ namespace ts { function isNarrowingBinaryExpression(expr: BinaryExpression) { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: + case SyntaxKind.BarBarEqualsToken: + case SyntaxKind.AmpersandAmpersandEqualsToken: + case SyntaxKind.QuestionQuestionEqualsToken: return containsNarrowableReference(expr.left); case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f53eb42e6a2..c08d2a2348b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20701,7 +20701,11 @@ namespace ts { function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { switch (expr.operatorToken.kind) { case SyntaxKind.EqualsToken: + case SyntaxKind.BarBarEqualsToken: + case SyntaxKind.AmpersandAmpersandEqualsToken: + case SyntaxKind.QuestionQuestionEqualsToken: return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue); + case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: diff --git a/tests/baselines/reference/logicalAssignment4(target=es2015).errors.txt b/tests/baselines/reference/logicalAssignment4(target=es2015).errors.txt index b8f87f62ca1..ee34fac607c 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2015).errors.txt +++ b/tests/baselines/reference/logicalAssignment4(target=es2015).errors.txt @@ -1,7 +1,8 @@ -tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(39,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(45,13): error TS2532: Object is possibly 'undefined'. -==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (1 errors) ==== +==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (2 errors) ==== function foo1(results: number[] | undefined) { (results ||= []).push(100); } @@ -24,10 +25,33 @@ tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): e name: string; original?: ThingWithOriginal } - function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); - ~~~~~ + declare const v: number + function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ !!! error TS2532: Object is possibly 'undefined'. + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + } } } \ No newline at end of file diff --git a/tests/baselines/reference/logicalAssignment4(target=es2015).js b/tests/baselines/reference/logicalAssignment4(target=es2015).js index 187ca2ed475..b54bfb6d487 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2015).js +++ b/tests/baselines/reference/logicalAssignment4(target=es2015).js @@ -21,9 +21,30 @@ interface ThingWithOriginal { name: string; original?: ThingWithOriginal } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); +declare const v: number +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + } } } @@ -43,8 +64,28 @@ function foo4(results) { results !== null && results !== void 0 ? results : (results = []); results.push(100); } -function doSomethingWithAlias(thing) { - if (thing && (thing = thing.original)) { - console.log(thing.name); +function doSomethingWithAlias(thing, defaultValue) { + if (v === 1) { + if (thing && (thing = thing.original)) { + thing.name; + } + } + else if (v === 2) { + if (thing && (thing = defaultValue)) { + thing.name; + defaultValue.name; + } + } + else if (v === 3) { + if (thing || (thing = defaultValue)) { + thing.name; + defaultValue.name; + } + } + else { + if (thing !== null && thing !== void 0 ? thing : (thing = defaultValue)) { + thing.name; + defaultValue.name; + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=es2015).symbols b/tests/baselines/reference/logicalAssignment4(target=es2015).symbols index 8c8fdae296c..46a02a48110 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2015).symbols +++ b/tests/baselines/reference/logicalAssignment4(target=es2015).symbols @@ -55,23 +55,81 @@ interface ThingWithOriginal { >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 21, 1)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +declare const v: number +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 22, 23)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) - if (thing &&= thing.original) { ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) + if (v === 1) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= thing.original) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >thing.original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) - console.log(thing.name); ->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, --, --)) + thing.name; >thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 2) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 3) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing ||= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else { + if (thing ??= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=es2015).types b/tests/baselines/reference/logicalAssignment4(target=es2015).types index 337f639d502..6a044ae0e1b 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2015).types +++ b/tests/baselines/reference/logicalAssignment4(target=es2015).types @@ -70,24 +70,89 @@ interface ThingWithOriginal { original?: ThingWithOriginal >original : ThingWithOriginal | undefined } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : (thing?: ThingWithOriginal | undefined) => void ->thing : ThingWithOriginal | undefined +declare const v: number +>v : number - if (thing &&= thing.original) { +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : (thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) => void +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + if (v === 1) { +>v === 1 : boolean +>v : number +>1 : 1 + + if (thing &&= thing.original) { >thing &&= thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal | undefined >thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal >original : ThingWithOriginal | undefined - console.log(thing.name); ->console.log(thing.name) : void ->console.log : (...data: any[]) => void ->console : Console ->log : (...data: any[]) => void + thing.name; >thing.name : string ->thing : ThingWithOriginal | undefined +>thing : ThingWithOriginal >name : string + } + } + else if (v === 2) { +>v === 2 : boolean +>v : number +>2 : 2 + + if (thing &&= defaultValue) { +>thing &&= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name +>defaultValue.name : string +>defaultValue : ThingWithOriginal +>name : string + } + } + else if (v === 3) { +>v === 3 : boolean +>v : number +>3 : 3 + + if (thing ||= defaultValue) { +>thing ||= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } + } + else { + if (thing ??= defaultValue) { +>thing ??= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=es2020).errors.txt b/tests/baselines/reference/logicalAssignment4(target=es2020).errors.txt index b8f87f62ca1..ee34fac607c 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2020).errors.txt +++ b/tests/baselines/reference/logicalAssignment4(target=es2020).errors.txt @@ -1,7 +1,8 @@ -tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(39,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(45,13): error TS2532: Object is possibly 'undefined'. -==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (1 errors) ==== +==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (2 errors) ==== function foo1(results: number[] | undefined) { (results ||= []).push(100); } @@ -24,10 +25,33 @@ tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): e name: string; original?: ThingWithOriginal } - function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); - ~~~~~ + declare const v: number + function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ !!! error TS2532: Object is possibly 'undefined'. + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + } } } \ No newline at end of file diff --git a/tests/baselines/reference/logicalAssignment4(target=es2020).js b/tests/baselines/reference/logicalAssignment4(target=es2020).js index 3285cef381a..b2dc9ae3ce9 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2020).js +++ b/tests/baselines/reference/logicalAssignment4(target=es2020).js @@ -21,9 +21,30 @@ interface ThingWithOriginal { name: string; original?: ThingWithOriginal } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); +declare const v: number +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + } } } @@ -43,8 +64,28 @@ function foo4(results) { results ?? (results = []); results.push(100); } -function doSomethingWithAlias(thing) { - if (thing && (thing = thing.original)) { - console.log(thing.name); +function doSomethingWithAlias(thing, defaultValue) { + if (v === 1) { + if (thing && (thing = thing.original)) { + thing.name; + } + } + else if (v === 2) { + if (thing && (thing = defaultValue)) { + thing.name; + defaultValue.name; + } + } + else if (v === 3) { + if (thing || (thing = defaultValue)) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ?? (thing = defaultValue)) { + thing.name; + defaultValue.name; + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=es2020).symbols b/tests/baselines/reference/logicalAssignment4(target=es2020).symbols index 8c8fdae296c..46a02a48110 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2020).symbols +++ b/tests/baselines/reference/logicalAssignment4(target=es2020).symbols @@ -55,23 +55,81 @@ interface ThingWithOriginal { >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 21, 1)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +declare const v: number +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 22, 23)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) - if (thing &&= thing.original) { ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) + if (v === 1) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= thing.original) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >thing.original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) - console.log(thing.name); ->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, --, --)) + thing.name; >thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 2) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 3) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing ||= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else { + if (thing ??= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=es2020).types b/tests/baselines/reference/logicalAssignment4(target=es2020).types index 337f639d502..6a044ae0e1b 100644 --- a/tests/baselines/reference/logicalAssignment4(target=es2020).types +++ b/tests/baselines/reference/logicalAssignment4(target=es2020).types @@ -70,24 +70,89 @@ interface ThingWithOriginal { original?: ThingWithOriginal >original : ThingWithOriginal | undefined } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : (thing?: ThingWithOriginal | undefined) => void ->thing : ThingWithOriginal | undefined +declare const v: number +>v : number - if (thing &&= thing.original) { +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : (thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) => void +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + if (v === 1) { +>v === 1 : boolean +>v : number +>1 : 1 + + if (thing &&= thing.original) { >thing &&= thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal | undefined >thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal >original : ThingWithOriginal | undefined - console.log(thing.name); ->console.log(thing.name) : void ->console.log : (...data: any[]) => void ->console : Console ->log : (...data: any[]) => void + thing.name; >thing.name : string ->thing : ThingWithOriginal | undefined +>thing : ThingWithOriginal >name : string + } + } + else if (v === 2) { +>v === 2 : boolean +>v : number +>2 : 2 + + if (thing &&= defaultValue) { +>thing &&= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name +>defaultValue.name : string +>defaultValue : ThingWithOriginal +>name : string + } + } + else if (v === 3) { +>v === 3 : boolean +>v : number +>3 : 3 + + if (thing ||= defaultValue) { +>thing ||= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } + } + else { + if (thing ??= defaultValue) { +>thing ??= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=esnext).errors.txt b/tests/baselines/reference/logicalAssignment4(target=esnext).errors.txt index b8f87f62ca1..ee34fac607c 100644 --- a/tests/baselines/reference/logicalAssignment4(target=esnext).errors.txt +++ b/tests/baselines/reference/logicalAssignment4(target=esnext).errors.txt @@ -1,7 +1,8 @@ -tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(39,13): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(45,13): error TS2532: Object is possibly 'undefined'. -==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (1 errors) ==== +==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (2 errors) ==== function foo1(results: number[] | undefined) { (results ||= []).push(100); } @@ -24,10 +25,33 @@ tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): e name: string; original?: ThingWithOriginal } - function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); - ~~~~~ + declare const v: number + function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ !!! error TS2532: Object is possibly 'undefined'. + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + ~~~~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + } } } \ No newline at end of file diff --git a/tests/baselines/reference/logicalAssignment4(target=esnext).js b/tests/baselines/reference/logicalAssignment4(target=esnext).js index d9610ca60d3..5724bcaa58b 100644 --- a/tests/baselines/reference/logicalAssignment4(target=esnext).js +++ b/tests/baselines/reference/logicalAssignment4(target=esnext).js @@ -21,9 +21,30 @@ interface ThingWithOriginal { name: string; original?: ThingWithOriginal } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); +declare const v: number +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + } } } @@ -43,8 +64,28 @@ function foo4(results) { results ??= []; results.push(100); } -function doSomethingWithAlias(thing) { - if (thing &&= thing.original) { - console.log(thing.name); +function doSomethingWithAlias(thing, defaultValue) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name; + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=esnext).symbols b/tests/baselines/reference/logicalAssignment4(target=esnext).symbols index 8c8fdae296c..46a02a48110 100644 --- a/tests/baselines/reference/logicalAssignment4(target=esnext).symbols +++ b/tests/baselines/reference/logicalAssignment4(target=esnext).symbols @@ -55,23 +55,81 @@ interface ThingWithOriginal { >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 21, 1)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +declare const v: number +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 22, 23)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) >ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1)) - if (thing &&= thing.original) { ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) + if (v === 1) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= thing.original) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >thing.original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17)) - console.log(thing.name); ->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, --, --)) + thing.name; >thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) ->thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) >name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 2) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing &&= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else if (v === 3) { +>v : Symbol(v, Decl(logicalAssignment4.ts, 22, 13)) + + if (thing ||= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } + } + else { + if (thing ??= defaultValue) { +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) + + thing.name; +>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>thing : Symbol(thing, Decl(logicalAssignment4.ts, 23, 30)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + + defaultValue.name; +>defaultValue.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) +>defaultValue : Symbol(defaultValue, Decl(logicalAssignment4.ts, 23, 67)) +>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29)) + } } } diff --git a/tests/baselines/reference/logicalAssignment4(target=esnext).types b/tests/baselines/reference/logicalAssignment4(target=esnext).types index 337f639d502..6a044ae0e1b 100644 --- a/tests/baselines/reference/logicalAssignment4(target=esnext).types +++ b/tests/baselines/reference/logicalAssignment4(target=esnext).types @@ -70,24 +70,89 @@ interface ThingWithOriginal { original?: ThingWithOriginal >original : ThingWithOriginal | undefined } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { ->doSomethingWithAlias : (thing?: ThingWithOriginal | undefined) => void ->thing : ThingWithOriginal | undefined +declare const v: number +>v : number - if (thing &&= thing.original) { +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { +>doSomethingWithAlias : (thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) => void +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + if (v === 1) { +>v === 1 : boolean +>v : number +>1 : 1 + + if (thing &&= thing.original) { >thing &&= thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal | undefined >thing.original : ThingWithOriginal | undefined >thing : ThingWithOriginal >original : ThingWithOriginal | undefined - console.log(thing.name); ->console.log(thing.name) : void ->console.log : (...data: any[]) => void ->console : Console ->log : (...data: any[]) => void + thing.name; >thing.name : string ->thing : ThingWithOriginal | undefined +>thing : ThingWithOriginal >name : string + } + } + else if (v === 2) { +>v === 2 : boolean +>v : number +>2 : 2 + + if (thing &&= defaultValue) { +>thing &&= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name +>defaultValue.name : string +>defaultValue : ThingWithOriginal +>name : string + } + } + else if (v === 3) { +>v === 3 : boolean +>v : number +>3 : 3 + + if (thing ||= defaultValue) { +>thing ||= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } + } + else { + if (thing ??= defaultValue) { +>thing ??= defaultValue : ThingWithOriginal | undefined +>thing : ThingWithOriginal | undefined +>defaultValue : ThingWithOriginal | undefined + + thing.name; +>thing.name : string +>thing : ThingWithOriginal +>name : string + + defaultValue.name; +>defaultValue.name : string +>defaultValue : ThingWithOriginal | undefined +>name : string + } } } diff --git a/tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts b/tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts index 2ad97ed1fa1..bb13be7db6b 100644 --- a/tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts +++ b/tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts @@ -24,8 +24,29 @@ interface ThingWithOriginal { name: string; original?: ThingWithOriginal } -function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) { - if (thing &&= thing.original) { - console.log(thing.name); +declare const v: number +function doSomethingWithAlias(thing: ThingWithOriginal | undefined, defaultValue: ThingWithOriginal | undefined) { + if (v === 1) { + if (thing &&= thing.original) { + thing.name; + } + } + else if (v === 2) { + if (thing &&= defaultValue) { + thing.name; + defaultValue.name + } + } + else if (v === 3) { + if (thing ||= defaultValue) { + thing.name; + defaultValue.name; + } + } + else { + if (thing ??= defaultValue) { + thing.name; + defaultValue.name; + } } } \ No newline at end of file