When writing while
loops, I often run into the situation where I can be sure a certain value exists (connection
exists in the example) but the control flow analysis can not narrow it. Here's an example:
removeVertex(vertex: string) {
const connections = this.adjacencyList[vertex];
while (connections.length) {
const connection = connections.pop(); // <- This can not be undefined
this.removeEdge(connection!.node, vertex); // <- Unwanted casting
}
}
My general escape hatch is to just append !
to signal the compiler that a given type can not be undefined but I'm wondering if there is a more elegant way of solving this.
Edit fixed position of !
as suggested in the comments
CodePudding user response:
(Note: I'm assuming the !
in your question was misplaced, see this comment.)
There are at least a couple of things you can do:
- You can use a type assertion function
- You can rewrite the loop (in this particular case)
Type Assertion Function
The type assertion function is an assertion backed up by runtime checking (so you know it isn't incorrect):
function assertNotUndefined<T>(x: T): x is Exclude<T, undefined> {
if (x === undefined) {
throw new Error(`Value was undefined`);
}
}
Then the loop is:
removeVertex(vertex: string) {
const connections = this.adjacencyList[vertex];
while (connections.length) {
const connection = connections.pop();
assertNotUndefined(connection);
this.removeEdge(connection.node, vertex);
}
}
Rewriting the Loop
Another option in this specific case is to rewrite the looop slightly:
removeVertex(vertex: string) {
const connections = this.adjacencyList[vertex];
let connection: ConnectionType | undefined;
while ((connection = connections.pop()) !== undefined) {
this.removeEdge(connection.node, vertex);
}
}
...but that's specific to this exact loop. :-)