TypeScript utilizes control flow analysis to automatically narrow down the perceived type of a value to a subtype under specific conditions. This narrowing through control flow analysis is an incredibly valuable feature of TypeScript, as it eliminates the need for manual downcasting or asserting that a value of a certain type actually belongs to a subtype.
You may already be familiar with type guards, such as when you use typeOf checks on variables. For example:
function g(v: Foo) {
if (typeof v === "string") {
f(v); // compiles with no error
}
}
In this case, the compiler recognizes that v
has been narrowed from type Foo
to just string
. Without this analysis, you would have to write f(v as string)
even after confirming that v
is indeed a string
, leaving room for errors if you later change the check to typeof v === "number"
.
Your code also benefits from narrowing through control flow analysis:
If you have a variable of a union type (like v
of type Foo
, which is essentially string | number
), the type checker will narrow down the apparent type of the variable when you assign a value to the variable that matches one of the union members.
For instance, by assigning const v: Foo = "ok"
, the compiler narrows v
from string | number
to just string
. Subsequently, the compiler treats v
as type string
, enabling you to call
f(v)</code without any errors.</p>
<p>Without this analysis, you would have to resort to writing <code>f(v as string)
, which could introduce redundancy and potential bugs if you later changed the assignment to
const v: Foo = 123
.
Link to code playground