mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-03 18:38:40 -06:00
Fix "never nullish" diagnostic missing expressions wrapped in parentheses (#62789)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> Co-authored-by: Ryan Cavanaugh <ryanca@microsoft.com> Co-authored-by: Ryan Cavanaugh <RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
parent
632479f28d
commit
c574e4090d
@ -40548,12 +40548,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
checkNullishCoalesceOperandLeft(node);
|
||||
checkNullishCoalesceOperandRight(node);
|
||||
}
|
||||
|
||||
function checkNullishCoalesceOperandLeft(node: BinaryExpression) {
|
||||
const leftTarget = skipOuterExpressions(node.left, OuterExpressionKinds.All);
|
||||
|
||||
const nullishSemantics = getSyntacticNullishnessSemantics(leftTarget);
|
||||
if (nullishSemantics !== PredicateSemantics.Sometimes) {
|
||||
if (nullishSemantics === PredicateSemantics.Always) {
|
||||
@ -40565,25 +40563,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
function checkNullishCoalesceOperandRight(node: BinaryExpression) {
|
||||
const rightTarget = skipOuterExpressions(node.right, OuterExpressionKinds.All);
|
||||
const nullishSemantics = getSyntacticNullishnessSemantics(rightTarget);
|
||||
if (isNotWithinNullishCoalesceExpression(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nullishSemantics === PredicateSemantics.Always) {
|
||||
error(rightTarget, Diagnostics.This_expression_is_always_nullish);
|
||||
}
|
||||
else if (nullishSemantics === PredicateSemantics.Never) {
|
||||
error(rightTarget, Diagnostics.This_expression_is_never_nullish);
|
||||
}
|
||||
}
|
||||
|
||||
function isNotWithinNullishCoalesceExpression(node: BinaryExpression) {
|
||||
return !isBinaryExpression(node.parent) || node.parent.operatorToken.kind !== SyntaxKind.QuestionQuestionToken;
|
||||
}
|
||||
|
||||
function getSyntacticNullishnessSemantics(node: Node): PredicateSemantics {
|
||||
node = skipOuterExpressions(node);
|
||||
switch (node.kind) {
|
||||
@ -40601,15 +40580,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// List of operators that can produce null/undefined:
|
||||
// = ??= ?? || ||= && &&=
|
||||
switch ((node as BinaryExpression).operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
case SyntaxKind.BarBarToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
return PredicateSemantics.Sometimes;
|
||||
// For these operator kinds, the right operand is effectively controlling
|
||||
case SyntaxKind.CommaToken:
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return getSyntacticNullishnessSemantics((node as BinaryExpression).right);
|
||||
}
|
||||
return PredicateSemantics.Never;
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
neverNullishThroughParentheses.ts(6,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(7,14): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(10,15): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(11,16): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(14,15): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(15,16): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(16,17): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
neverNullishThroughParentheses.ts(16,17): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
|
||||
==== neverNullishThroughParentheses.ts (8 errors) ====
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
|
||||
const x: { y: string | undefined } | undefined = undefined as any;
|
||||
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
const foo = x?.y ?? `oops` ?? "";
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const bar = (x?.y ?? `oops`) ?? "";
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
// Additional test cases with various levels of nesting
|
||||
const baz = ((x?.y ?? `oops`)) ?? "";
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const qux = (((x?.y ?? `oops`))) ?? "";
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
// Test with different types
|
||||
const str1 = ("literal") ?? "fallback";
|
||||
~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const str2 = (("nested")) ?? "fallback";
|
||||
~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const nested = ("a" ?? "b") ?? "c";
|
||||
~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
36
tests/baselines/reference/neverNullishThroughParentheses.js
Normal file
36
tests/baselines/reference/neverNullishThroughParentheses.js
Normal file
@ -0,0 +1,36 @@
|
||||
//// [tests/cases/compiler/neverNullishThroughParentheses.ts] ////
|
||||
|
||||
//// [neverNullishThroughParentheses.ts]
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
|
||||
const x: { y: string | undefined } | undefined = undefined as any;
|
||||
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
const foo = x?.y ?? `oops` ?? "";
|
||||
const bar = (x?.y ?? `oops`) ?? "";
|
||||
|
||||
// Additional test cases with various levels of nesting
|
||||
const baz = ((x?.y ?? `oops`)) ?? "";
|
||||
const qux = (((x?.y ?? `oops`))) ?? "";
|
||||
|
||||
// Test with different types
|
||||
const str1 = ("literal") ?? "fallback";
|
||||
const str2 = (("nested")) ?? "fallback";
|
||||
const nested = ("a" ?? "b") ?? "c";
|
||||
|
||||
|
||||
//// [neverNullishThroughParentheses.js]
|
||||
"use strict";
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
||||
var x = undefined;
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
var foo = (_b = (_a = x === null || x === void 0 ? void 0 : x.y) !== null && _a !== void 0 ? _a : "oops") !== null && _b !== void 0 ? _b : "";
|
||||
var bar = (_d = ((_c = x === null || x === void 0 ? void 0 : x.y) !== null && _c !== void 0 ? _c : "oops")) !== null && _d !== void 0 ? _d : "";
|
||||
// Additional test cases with various levels of nesting
|
||||
var baz = (_f = (((_e = x === null || x === void 0 ? void 0 : x.y) !== null && _e !== void 0 ? _e : "oops"))) !== null && _f !== void 0 ? _f : "";
|
||||
var qux = (_h = ((((_g = x === null || x === void 0 ? void 0 : x.y) !== null && _g !== void 0 ? _g : "oops")))) !== null && _h !== void 0 ? _h : "";
|
||||
// Test with different types
|
||||
var str1 = (_j = ("literal")) !== null && _j !== void 0 ? _j : "fallback";
|
||||
var str2 = (_k = (("nested"))) !== null && _k !== void 0 ? _k : "fallback";
|
||||
var nested = (_l = ("a" !== null && "a" !== void 0 ? "a" : "b")) !== null && _l !== void 0 ? _l : "c";
|
||||
@ -0,0 +1,46 @@
|
||||
//// [tests/cases/compiler/neverNullishThroughParentheses.ts] ////
|
||||
|
||||
=== neverNullishThroughParentheses.ts ===
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
|
||||
const x: { y: string | undefined } | undefined = undefined as any;
|
||||
>x : Symbol(x, Decl(neverNullishThroughParentheses.ts, 2, 5))
|
||||
>y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
const foo = x?.y ?? `oops` ?? "";
|
||||
>foo : Symbol(foo, Decl(neverNullishThroughParentheses.ts, 5, 5))
|
||||
>x?.y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(neverNullishThroughParentheses.ts, 2, 5))
|
||||
>y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
|
||||
const bar = (x?.y ?? `oops`) ?? "";
|
||||
>bar : Symbol(bar, Decl(neverNullishThroughParentheses.ts, 6, 5))
|
||||
>x?.y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(neverNullishThroughParentheses.ts, 2, 5))
|
||||
>y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
|
||||
// Additional test cases with various levels of nesting
|
||||
const baz = ((x?.y ?? `oops`)) ?? "";
|
||||
>baz : Symbol(baz, Decl(neverNullishThroughParentheses.ts, 9, 5))
|
||||
>x?.y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(neverNullishThroughParentheses.ts, 2, 5))
|
||||
>y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
|
||||
const qux = (((x?.y ?? `oops`))) ?? "";
|
||||
>qux : Symbol(qux, Decl(neverNullishThroughParentheses.ts, 10, 5))
|
||||
>x?.y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(neverNullishThroughParentheses.ts, 2, 5))
|
||||
>y : Symbol(y, Decl(neverNullishThroughParentheses.ts, 2, 10))
|
||||
|
||||
// Test with different types
|
||||
const str1 = ("literal") ?? "fallback";
|
||||
>str1 : Symbol(str1, Decl(neverNullishThroughParentheses.ts, 13, 5))
|
||||
|
||||
const str2 = (("nested")) ?? "fallback";
|
||||
>str2 : Symbol(str2, Decl(neverNullishThroughParentheses.ts, 14, 5))
|
||||
|
||||
const nested = ("a" ?? "b") ?? "c";
|
||||
>nested : Symbol(nested, Decl(neverNullishThroughParentheses.ts, 15, 5))
|
||||
|
||||
144
tests/baselines/reference/neverNullishThroughParentheses.types
Normal file
144
tests/baselines/reference/neverNullishThroughParentheses.types
Normal file
@ -0,0 +1,144 @@
|
||||
//// [tests/cases/compiler/neverNullishThroughParentheses.ts] ////
|
||||
|
||||
=== neverNullishThroughParentheses.ts ===
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
|
||||
const x: { y: string | undefined } | undefined = undefined as any;
|
||||
>x : { y: string | undefined; } | undefined
|
||||
> : ^^^^^ ^^^^^^^^^^^^^^^
|
||||
>y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>undefined as any : any
|
||||
> : ^^^
|
||||
>undefined : undefined
|
||||
> : ^^^^^^^^^
|
||||
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
const foo = x?.y ?? `oops` ?? "";
|
||||
>foo : string
|
||||
> : ^^^^^^
|
||||
>x?.y ?? `oops` ?? "" : string
|
||||
> : ^^^^^^
|
||||
>x?.y ?? `oops` : string
|
||||
> : ^^^^^^
|
||||
>x?.y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>x : { y: string | undefined; } | undefined
|
||||
> : ^^^^^ ^^^^^^^^^^^^^^^
|
||||
>y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>`oops` : "oops"
|
||||
> : ^^^^^^
|
||||
>"" : ""
|
||||
> : ^^
|
||||
|
||||
const bar = (x?.y ?? `oops`) ?? "";
|
||||
>bar : string
|
||||
> : ^^^^^^
|
||||
>(x?.y ?? `oops`) ?? "" : string
|
||||
> : ^^^^^^
|
||||
>(x?.y ?? `oops`) : string
|
||||
> : ^^^^^^
|
||||
>x?.y ?? `oops` : string
|
||||
> : ^^^^^^
|
||||
>x?.y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>x : { y: string | undefined; } | undefined
|
||||
> : ^^^^^ ^^^^^^^^^^^^^^^
|
||||
>y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>`oops` : "oops"
|
||||
> : ^^^^^^
|
||||
>"" : ""
|
||||
> : ^^
|
||||
|
||||
// Additional test cases with various levels of nesting
|
||||
const baz = ((x?.y ?? `oops`)) ?? "";
|
||||
>baz : string
|
||||
> : ^^^^^^
|
||||
>((x?.y ?? `oops`)) ?? "" : string
|
||||
> : ^^^^^^
|
||||
>((x?.y ?? `oops`)) : string
|
||||
> : ^^^^^^
|
||||
>(x?.y ?? `oops`) : string
|
||||
> : ^^^^^^
|
||||
>x?.y ?? `oops` : string
|
||||
> : ^^^^^^
|
||||
>x?.y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>x : { y: string | undefined; } | undefined
|
||||
> : ^^^^^ ^^^^^^^^^^^^^^^
|
||||
>y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>`oops` : "oops"
|
||||
> : ^^^^^^
|
||||
>"" : ""
|
||||
> : ^^
|
||||
|
||||
const qux = (((x?.y ?? `oops`))) ?? "";
|
||||
>qux : string
|
||||
> : ^^^^^^
|
||||
>(((x?.y ?? `oops`))) ?? "" : string
|
||||
> : ^^^^^^
|
||||
>(((x?.y ?? `oops`))) : string
|
||||
> : ^^^^^^
|
||||
>((x?.y ?? `oops`)) : string
|
||||
> : ^^^^^^
|
||||
>(x?.y ?? `oops`) : string
|
||||
> : ^^^^^^
|
||||
>x?.y ?? `oops` : string
|
||||
> : ^^^^^^
|
||||
>x?.y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>x : { y: string | undefined; } | undefined
|
||||
> : ^^^^^ ^^^^^^^^^^^^^^^
|
||||
>y : string | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>`oops` : "oops"
|
||||
> : ^^^^^^
|
||||
>"" : ""
|
||||
> : ^^
|
||||
|
||||
// Test with different types
|
||||
const str1 = ("literal") ?? "fallback";
|
||||
>str1 : "literal"
|
||||
> : ^^^^^^^^^
|
||||
>("literal") ?? "fallback" : "literal"
|
||||
> : ^^^^^^^^^
|
||||
>("literal") : "literal"
|
||||
> : ^^^^^^^^^
|
||||
>"literal" : "literal"
|
||||
> : ^^^^^^^^^
|
||||
>"fallback" : "fallback"
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
const str2 = (("nested")) ?? "fallback";
|
||||
>str2 : "nested"
|
||||
> : ^^^^^^^^
|
||||
>(("nested")) ?? "fallback" : "nested"
|
||||
> : ^^^^^^^^
|
||||
>(("nested")) : "nested"
|
||||
> : ^^^^^^^^
|
||||
>("nested") : "nested"
|
||||
> : ^^^^^^^^
|
||||
>"nested" : "nested"
|
||||
> : ^^^^^^^^
|
||||
>"fallback" : "fallback"
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
const nested = ("a" ?? "b") ?? "c";
|
||||
>nested : "a"
|
||||
> : ^^^
|
||||
>("a" ?? "b") ?? "c" : "a"
|
||||
> : ^^^
|
||||
>("a" ?? "b") : "a"
|
||||
> : ^^^
|
||||
>"a" ?? "b" : "a"
|
||||
> : ^^^
|
||||
>"a" : "a"
|
||||
> : ^^^
|
||||
>"b" : "b"
|
||||
> : ^^^
|
||||
>"c" : "c"
|
||||
> : ^^^
|
||||
|
||||
@ -7,26 +7,26 @@ predicateSemantics.ts(29,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(30,13): error TS2872: This kind of expression is always truthy.
|
||||
predicateSemantics.ts(31,13): error TS2872: This kind of expression is always truthy.
|
||||
predicateSemantics.ts(32,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(32,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(32,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(33,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(34,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(34,22): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(36,20): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(37,20): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(34,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(36,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(37,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(38,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(39,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(40,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(40,29): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(41,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(42,20): error TS2881: This expression is never nullish.
|
||||
predicateSemantics.ts(43,21): error TS2881: This expression is never nullish.
|
||||
predicateSemantics.ts(40,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(41,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(42,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
predicateSemantics.ts(43,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
predicateSemantics.ts(45,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(45,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(45,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(45,21): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(45,29): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(46,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(46,21): error TS2881: This expression is never nullish.
|
||||
predicateSemantics.ts(46,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
predicateSemantics.ts(47,13): error TS2871: This expression is always nullish.
|
||||
predicateSemantics.ts(47,22): error TS2881: This expression is never nullish.
|
||||
predicateSemantics.ts(47,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
predicateSemantics.ts(50,8): error TS2872: This kind of expression is always truthy.
|
||||
predicateSemantics.ts(51,11): error TS2872: This kind of expression is always truthy.
|
||||
predicateSemantics.ts(52,8): error TS2872: This kind of expression is always truthy.
|
||||
@ -89,7 +89,7 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be
|
||||
const p07 = null ?? null ?? null;
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p08 = null ?? opt ?? null;
|
||||
~~~~
|
||||
@ -97,14 +97,14 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be
|
||||
const p09 = null ?? (opt ? null : undefined) ?? null;
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
|
||||
const p10 = opt ?? null ?? 1;
|
||||
~~~~
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p11 = opt ?? null ?? null;
|
||||
~~~~
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p12 = opt ?? (null ?? 1);
|
||||
~~~~
|
||||
@ -115,35 +115,35 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be
|
||||
const p14 = opt ?? (null ?? null ?? null);
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p15 = opt ?? (opt ? null : undefined) ?? null;
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p16 = opt ?? 1 ?? 2;
|
||||
~
|
||||
!!! error TS2881: This expression is never nullish.
|
||||
~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const p17 = opt ?? (opt ? 1 : 2) ?? 3;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2881: This expression is never nullish.
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
const p21 = null ?? null ?? null ?? null;
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
const p22 = null ?? 1 ?? 1;
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~
|
||||
!!! error TS2881: This expression is never nullish.
|
||||
~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
const p23 = null ?? (opt ? 1 : 2) ?? 1;
|
||||
~~~~
|
||||
!!! error TS2871: This expression is always nullish.
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2881: This expression is never nullish.
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
|
||||
|
||||
// Outer expression tests
|
||||
while ({} as any) { }
|
||||
|
||||
18
tests/cases/compiler/neverNullishThroughParentheses.ts
Normal file
18
tests/cases/compiler/neverNullishThroughParentheses.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// @strict: true
|
||||
|
||||
// Repro for issue where "never nullish" checks miss "never nullish" through parentheses
|
||||
|
||||
const x: { y: string | undefined } | undefined = undefined as any;
|
||||
|
||||
// Both should error - both expressions are guaranteed to be "oops"
|
||||
const foo = x?.y ?? `oops` ?? "";
|
||||
const bar = (x?.y ?? `oops`) ?? "";
|
||||
|
||||
// Additional test cases with various levels of nesting
|
||||
const baz = ((x?.y ?? `oops`)) ?? "";
|
||||
const qux = (((x?.y ?? `oops`))) ?? "";
|
||||
|
||||
// Test with different types
|
||||
const str1 = ("literal") ?? "fallback";
|
||||
const str2 = (("nested")) ?? "fallback";
|
||||
const nested = ("a" ?? "b") ?? "c";
|
||||
Loading…
x
Reference in New Issue
Block a user