mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
fix(51760): Nullish-coalescing assignment narrows type to assigned value (#51767)
* fix(51760): skip type guard errors for narrowed nullish-coalescing assignment * update tests
This commit is contained in:
@@ -26819,7 +26819,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
|
||||
// for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a`
|
||||
if (isExpressionOfOptionalChainRoot(expr) ||
|
||||
isBinaryExpression(expr.parent) && expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken && expr.parent.left === expr) {
|
||||
isBinaryExpression(expr.parent) && (expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken || expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionEqualsToken) && expr.parent.left === expr) {
|
||||
return narrowTypeByOptionality(type, expr, assumeTrue);
|
||||
}
|
||||
switch (expr.kind) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//// [equalityWithtNullishCoalescingAssignment.ts]
|
||||
function f1(a?: boolean): void {
|
||||
a ??= true;
|
||||
|
||||
if (a === false) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
|
||||
function f2() {
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
x ??= 1;
|
||||
if (x === 0) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [equalityWithtNullishCoalescingAssignment.js]
|
||||
function f1(a) {
|
||||
a !== null && a !== void 0 ? a : (a = true);
|
||||
if (a === false) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
function f2() {
|
||||
var x = 0;
|
||||
x !== null && x !== void 0 ? x : (x = 1);
|
||||
if (x === 0) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithtNullishCoalescingAssignment.ts ===
|
||||
function f1(a?: boolean): void {
|
||||
>f1 : Symbol(f1, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
a ??= true;
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
if (a === false) {
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
console.log(a);
|
||||
>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, --, --))
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
>f1 : Symbol(f1, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 0))
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(equalityWithtNullishCoalescingAssignment.ts, 7, 10))
|
||||
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
x ??= 1;
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
if (x === 0) {
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
console.log(x);
|
||||
>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, --, --))
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithtNullishCoalescingAssignment.ts ===
|
||||
function f1(a?: boolean): void {
|
||||
>f1 : (a?: boolean) => void
|
||||
>a : boolean
|
||||
|
||||
a ??= true;
|
||||
>a ??= true : boolean
|
||||
>a : boolean
|
||||
>true : true
|
||||
|
||||
if (a === false) {
|
||||
>a === false : boolean
|
||||
>a : boolean
|
||||
>false : false
|
||||
|
||||
console.log(a);
|
||||
>console.log(a) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>a : false
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
>f1(false) : void
|
||||
>f1 : (a?: boolean) => void
|
||||
>false : false
|
||||
|
||||
function f2() {
|
||||
>f2 : () => void
|
||||
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>0 as any : any
|
||||
>0 : 0
|
||||
|
||||
x ??= 1;
|
||||
>x ??= 1 : 0 | 1 | 2 | 3
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>1 : 1
|
||||
|
||||
if (x === 0) {
|
||||
>x === 0 : boolean
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>0 : 0
|
||||
|
||||
console.log(x);
|
||||
>console.log(x) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>x : 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//// [equalityWithtNullishCoalescingAssignment.ts]
|
||||
function f1(a?: boolean): void {
|
||||
a ??= true;
|
||||
|
||||
if (a === false) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
|
||||
function f2() {
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
x ??= 1;
|
||||
if (x === 0) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [equalityWithtNullishCoalescingAssignment.js]
|
||||
"use strict";
|
||||
function f1(a) {
|
||||
a !== null && a !== void 0 ? a : (a = true);
|
||||
if (a === false) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
function f2() {
|
||||
var x = 0;
|
||||
x !== null && x !== void 0 ? x : (x = 1);
|
||||
if (x === 0) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithtNullishCoalescingAssignment.ts ===
|
||||
function f1(a?: boolean): void {
|
||||
>f1 : Symbol(f1, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
a ??= true;
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
if (a === false) {
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
|
||||
console.log(a);
|
||||
>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, --, --))
|
||||
>a : Symbol(a, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 12))
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
>f1 : Symbol(f1, Decl(equalityWithtNullishCoalescingAssignment.ts, 0, 0))
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(equalityWithtNullishCoalescingAssignment.ts, 7, 10))
|
||||
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
x ??= 1;
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
if (x === 0) {
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
|
||||
console.log(x);
|
||||
>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, --, --))
|
||||
>x : Symbol(x, Decl(equalityWithtNullishCoalescingAssignment.ts, 10, 7))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithtNullishCoalescingAssignment.ts ===
|
||||
function f1(a?: boolean): void {
|
||||
>f1 : (a?: boolean) => void
|
||||
>a : boolean | undefined
|
||||
|
||||
a ??= true;
|
||||
>a ??= true : boolean
|
||||
>a : boolean | undefined
|
||||
>true : true
|
||||
|
||||
if (a === false) {
|
||||
>a === false : boolean
|
||||
>a : boolean
|
||||
>false : false
|
||||
|
||||
console.log(a);
|
||||
>console.log(a) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>a : false
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
>f1(false) : void
|
||||
>f1 : (a?: boolean | undefined) => void
|
||||
>false : false
|
||||
|
||||
function f2() {
|
||||
>f2 : () => void
|
||||
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>0 as any : any
|
||||
>0 : 0
|
||||
|
||||
x ??= 1;
|
||||
>x ??= 1 : 0 | 1 | 2 | 3
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>1 : 1
|
||||
|
||||
if (x === 0) {
|
||||
>x === 0 : boolean
|
||||
>x : 0 | 1 | 2 | 3
|
||||
>0 : 0
|
||||
|
||||
console.log(x);
|
||||
>console.log(x) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>x : 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// @strict: true, false
|
||||
|
||||
function f1(a?: boolean): void {
|
||||
a ??= true;
|
||||
|
||||
if (a === false) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
f1(false);
|
||||
|
||||
function f2() {
|
||||
let x: 0 | 1 | 2 | 3 = 0 as any;
|
||||
x ??= 1;
|
||||
if (x === 0) {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user