-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
strictNullChecks false positives in case clause #24091
Comments
Wow I've never seen anyone do that with a switch/case. I don't know how easy it is to add this to our narrowing logic, but I'll mark it as a bug. |
This isn't unique to switch-case - this also doesn't work: function test1(param?: { prop: string }) {
if ((param && param.prop) === "foo") {
return param.prop;
}
} which is equivalent to the switch-case above. And, similarly/simplified a bit: function test1(param?: { prop: string | number }): "no" | { prop: string | number } {
if ((param && "foo") === "foo") {
return param; // error
}
return "no";
} The root cause looks like it's because when we start diving into |
I think I've just come across this same issue. The strict-null check doesn't work when the check is contained in an other function. type NullOrString = string | null
const testForNull = (param : NullOrString) => param != null
const doStringStuff = (param : String) => { /* ... */ }
const doSomething = (param: NullOrString) =>
{
if(param != null)
doStringStuff(param)
}
const doSamething = (param: NullOrString) =>
{
if(testForNull(param))
doStringStuff(param)
} The doSamething-function will give this error:
|
@defenestrant see #10734 or similar issues |
@weswigham @RyanCavanaugh @DanielRosenwasser - this is a common pattern in JavaScript, not only in TypeScript's own codebase. ;-) Any time you want to switch on a property value or array member of a nullable object, you need to first make sure that the object isn't null or undefined. This is easily done via The best workaround I found is to transform the Other workarounds like wrapping the switch in Here's simple examples of the broken cases and the (bad, IMHO) workarounds available in TypeScript 3.1. // compiled with strictNullChecks
function repro (x: string[] | null) {
// broken
switch (x && x.length) {
case 1:
console.log (x[0]); // compiler error: Object is possibly null
break;
default:
console.log ('invalid x');
break;
}
// broken also-- illustrates that root cause is not switch vs. if
if ((x && x.length)===1) {
console.log (x[0]); // compiler error: Object is possibly null
} else {
console.log ('invalid x');
}
// workaround 1: convert to if
if (x && x.length===1) {
console.log (x[0]); // no compiler error
} else {
console.log ('invalid x');
}
// workaround 2: wrap switch with null check. duplicates error handling code!
if (x) {
switch (x && x.length) {
case 1:
console.log (x[0]); // no compiler error
break;
default:
console.log ('invalid x');
break;
}
} else {
console.log ('invalid x');
}
// workaround 3: nested switch statements. awful!
switch (x) {
case null:
case undefined:
console.log ('invalid x');
break;
default:
switch (x.length) { // no compiler error
case 1:
console.log (x[0]); // no compiler error
break;
default:
console.log ('invalid x');
}
break;
}
// workaround 4: extract into local variables outside the switch. cumbersome!
const len = x && x.length; // no compiler error
const first = x && x.length && x[0]; // no compiler error
switch (len) {
case 1:
console.log (first);
break;
default:
console.log ('invalid x');
break;
}
// workaround 5: use non-null type assertion. not type safe!
switch (x && x.length) {
case 1:
console.log (x![0]); // no compiler error (but could hide real type-safety errors later)
break;
default:
console.log ('invalid x');
break;
}
} |
I have a similar issue, but it doesn't regard type TestType = { type: "a", a: number } | { type: "b", b: number }
function test(obj: TestType | null): number {
switch (obj && obj.type) {
case null:
return 0
case "a":
return obj.a // Property 'a' does not exist on type 'TestType'. Property 'a' does not exist on type '{ type: "b"; b: number; }'.
case "b":
return obj.b // Property 'b' does not exist on type 'TestType'. Property 'b' does not exist on type '{ type: "a"; a: number; }'.
}
throw new Error("unreachable")
} |
Not sure if fits on this issue or not, but here's an example of false positive I'm facing: Link: Playground (ps: enable interface Obj { a: number }
function test(obj?: Obj) {
const hasA = !!(obj && obj.a)
// Correct: Shows warning
console.log(obj.a)
// Correct: Doesn't show warning
if (obj) {
console.log(obj.a)
}
// Wrong: Should not show warning
if (hasA) {
console.log(obj.a)
}
}
test()
test({ a: 1 }) |
Apologies for bumping this after so long, but I've also stumbled across this issue in React TSX files. Here:
In this use case I can get around it in other ways, but it does make it less pretty. |
TypeScript Version: 2.9.0-dev.20180512
Search Terms:
Code
Expected behavior:
Compiles without error.
Actual behavior:
strictNullChecks errors as described in the comments above.
Playground Link: https://agentcooper.github.io/typescript-play/?noImplicitReturns=false#code/GYVwdgxgLglg9mABFApgZygRgBQAcCGATvgLYD8AXIgN66Fy5UaExgDmAvgJQ0BQiiNAHcYUCAAtEeIqUQAyOYgLESAOjoMe1fgMQR8aFIgDkwOHGMUduxIRRQQhJMtLr6uANyIA9N8QpCekIqYxcSY0QYNCU4NDQYACMAGwBPRHAAExRgVhQMnQ5eQt5QSFgEZHQoACZpFSpad0pBKBZ2bj4BYVEJKTD5RTC3TU7dfUMTMwsrGwE7ByclGTUNXFUJIgBBKGwABi4vX39AuGCTIdWIqJi4xNT0sCycsDyCoqA
Related Issues:
#23818
The text was updated successfully, but these errors were encountered: