-
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
Type narrowing with union types create impossible case with else statement #58541
Comments
Not a bug. Types are narrowed on assignment, so TS knows it's impossible for that
|
Oh, I've provided a bad example here. It still happens when the value is not known (in a function) for me in some places It seems to happen when there are nested type unions? type Thing<T> = {
op: 'a' | 'b'
v: T
} | {
op: 'c' | 'd'
v1: T
v2: T
} | T | T[];
function test(columns: { value: Thing<number | string> | undefined | null }[]): void {
for (const { value } of columns) {
if (value instanceof Array) {
// this is fine
} else if (typeof value == 'object' && value != null) {
if (value.op == 'c' || value.op == 'd') {
// this is fine
value.op
value.v1
value.v2
} else {
// ts knows value.op can only be 'a' | 'b'
if (value.op == 'c' || value.op == 'd') value
// but v is still not defined
value.v
}
} else if (value != null) {
// string | number
value
}
}
} |
That's a much more instructive example, thanks. I'd recommend replacing the example in the OP with it since it perfectly illustrates the actual problem you're facing.
edit: That second paragraph is probably wrong. See Ryan's reply below. |
The simplest form looks like this: type Thing<T> =
| { op: 'a', a: T }
| { op: 'c' | 'd', cd: T };
function test(value: Thing<number | string>): void {
if (value.op === 'c' || value.op === 'd') {
// this is fine
value.op
value.cd
} else {
// ts knows value.op can only be 'a'
value.op
// ^?
// but no a property
value.a
}
} This is a duplicate of #31404 but I'll ping some folks to take another bite at the apple; maybe it's more tractable these days |
Ah, so it's just the union-typed discriminant that's throwing it off? I figured it was because |
The TL;DR is that from the control flow analyzer's perspective, the code looks like this type Thing<T> =
| { op: 'a', a: T }
| { op: 'c' | 'd', cd: T };
function test(value: Thing<number | string>): void {
if (value.op === 'c') {
// this is fine
value.op
value.cd
} else if (value.op === 'd') {
// this is fine
value.op
value.cd
} else {
// ts knows value.op can only be 'a'
value.op
// ^?
// but no a property
value.a
}
} By exclusion, |
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
🔎 Search Terms
else
type narrowing
🕗 Version & Regression Information
⏯ Playground Link
EDIT: this is a bad example
https://www.typescriptlang.org/play/?ts=5.4.5#code/C4TwDgpgBAQgrgcygXigbwFBW1AhgLigHIAeZIgGixwCNCA7OAWxogCcMBfKAH3WuwFiAPnJUcUAMYNmrDpwwYA9EqgATAPYQAzvSLAoAdw1sA1gH4MkjfW0HgO4IXhJUmCUNJiBUOlABMXBgAlgBmUAAUDnYAdLgoqF5EAJT8Eiq+UBAAHsF22nj0alJSuPT0GsA+1rYaADYQMXUaCFGOMTTJ1Tba9Y3NrdHAMZJd3BB12tDuOBnB9FC9TNCSuFMFwAAW7NB5eFAARNZMYLhseTZ4YJBnBXD08w70wME2uHUHWWxsJlBhUABJKDANggYEaKQaE5naBDOI+DL0CDBLbsEq-GhZXJ2KDbNjQCAANwgCy2GkQm32TDgONYInIhWKqPxoRMKyg1JxOTyVQkNV6DSaLTasU63VqgoGIuGoyCylUNDg9k2e2MZm0GFC90kL0uQ38UWciFSM2w-yicQSxDIKTSEhw-L6QsGHS6EnGk2mPj5PSdUplbpwCk4QA
💻 Code
EDIT: still a bad example, assume
test
is not known🙁 Actual behavior
else
statement does not type narrow properly in some cases.In my code it's impossible to get around this as the type narrowing DOES work properly in further if statements, which prevents me from simply checking with the same comparison again with a return statement.
The example given uses the value of
a
to determine whether to useb
orc
, but the narrowing doesn't allow any code in theelse
to use either.🙂 Expected behavior
The type narrowing checks for the
if
condition inside theelse
block should also apply to other code in theelse
block.Additional information about the issue
The text was updated successfully, but these errors were encountered: