You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Type definitionexporttypeExampleType=|{paramA: "a"|"b";paramB: number;paramC: number;}|{paramA: "c"|"d";paramB: number};// Function with type narrowing issuefunctionrunExample({ example }: {example: ExampleType}){if(example.paramA==="b"||example.paramA==="c"||example.paramA==="d"){returnexample.paramB;}returnexample.paramC;// Type narrowing issue here}
π Actual behavior
The TypeScript type narrowing is not working as expected. Even when the example.paramA is narrowed down to "c" or "d" inside the if statement, TypeScript still considers it a union of all possible types, resulting in a type error when trying to access example.paramC.
π Expected behavior
I expected TypeScript to correctly narrow down the type of example inside the if statement, so that accessing example.paramC would not result in a type error when example.paramA not is "b", "c" or "d".
Additional information about the issue
Let's imagine that I have a TS type that can represent two data types. The first one allows paramA to be "a" or "b", and in this case, it has two additional parameters, paramB and paramC. The other type also has paramA, but it can be "c" or "d". However, in these latter two cases, it only has an additional parameter paramB. In other words, paramC only exists when paramA is exclusively "a" or "b".
So, I perform type narrowing using if() statements that check if paramA is "b", "c", or "d", then it will return the value of paramB. Otherwise, it is understood that paramA is "a" since it is the only option available, so we return paramC.
Note that this rule matches the requirement mentioned earlier. So, only when paramA is "a" or "b", we can access paramB and paramC, and when paramA is "c" or "d", we have only one parameter paramB, and paramC is not available.
Therefore, we can understand that the following construction would be valid:
functionrunExample({ example }: {example: ExampleType}){if(example.paramA==="b"||example.paramA==="c"||example.paramA==="d"){returnexample.paramB;}returnexample.paramC;}
However, as it is, we will have an error in paramC of the last return with the following message:
Property 'paramC' does not exist on type 'ExampleType'. Did you mean 'paramA'?
Property 'paramC' does not exist on type '{ paramA: "c" | "d"; paramB: number; }'.(2551)
In other words, even though the if() statement captures the second type (where paramA is "c" or "d"), at this point, example is still treated as a "composite type" between the two possibilities, and type narrowing is not performed correctly.
However, if I adjust the type definition to the following:
π Search Terms
narrowing two possibilities type
π Version & Regression Information
This is the behavior in every version
5.2.2
,4.9.5
,3.9.7
, and I reviewed the FAQ for entries about type narrowing issues.β― Playground Link
https://www.typescriptlang.org/play?target=9&jsx=4#code/KYDwDg9gTgLgBDAnmYcCiICGBbMAbYAFWVQF4AoOOAHzgG9KqmxMocBBALjgCJMeavAEY8A3IyZwWbbACFuAOwCu2IcCjjJVaTgDCilWo0S4AX0a06U1h248AxgNo8AJmOsz5cZavVnx5ABmSgr2MACWEApwUCEYOPjAABRWoAkEZtypWLgE3PG5RCRmAJT0jOGBcEkmaYUAdDrY7HCkbcJO1LU5iY02za3tDp3d6cB9Mi1tpLxujGUMklDAMEpQ0XW9TbKaZuSMy6vrcJsEE3ri5kA
π» Code
π Actual behavior
The TypeScript type narrowing is not working as expected. Even when the
example.paramA
is narrowed down to"c"
or"d"
inside theif
statement, TypeScript still considers it a union of all possible types, resulting in a type error when trying to accessexample.paramC
.π Expected behavior
I expected TypeScript to correctly narrow down the type of example inside the
if
statement, so that accessingexample.paramC
would not result in a type error whenexample.paramA
not is"b"
,"c"
or"d"
.Additional information about the issue
Let's imagine that I have a TS type that can represent two data types. The first one allows
paramA
to be"a"
or"b"
, and in this case, it has two additional parameters,paramB
andparamC
. The other type also hasparamA
, but it can be"c"
or"d"
. However, in these latter two cases, it only has an additional parameterparamB
. In other words,paramC
only exists whenparamA
is exclusively"a"
or"b"
.So, I perform type narrowing using
if()
statements that check ifparamA
is"b"
,"c"
, or"d"
, then it will return the value ofparamB
. Otherwise, it is understood thatparamA
is"a"
since it is the only option available, so we returnparamC
.Here is my ExampleType type signature:
Note that this rule matches the requirement mentioned earlier. So, only when
paramA
is"a"
or"b"
, we can accessparamB
andparamC
, and whenparamA
is"c"
or"d",
we have only one parameterparamB
, andparamC
is not available.Therefore, we can understand that the following construction would be valid:
However, as it is, we will have an error in
paramC
of the lastreturn
with the following message:In other words, even though the
if()
statement captures the second type (whereparamA
is"c"
or"d"
), at this point, example is still treated as a "composite type" between the two possibilities, and type narrowing is not performed correctly.However, if I adjust the type definition to the following:
Then the code works correctly and identifies the last
example
as the first available type only.Therefore, it can be concluded that when
paramA
allows"c"
or"d"
, TypeScript is unable to perform type narrowing correctly.The text was updated successfully, but these errors were encountered: