๐ŸŽ“ A1Learner
๐Ÿ”
0 of 42 lessons completed

TypeScript Narrowing in Depth

Narrowing inside loops refines each element of a union one value at a time. typeof and truthiness checks sort mixed values into narrower collections.

typeof narrowing in a loop

The loop visits a mixed array one element at a time. Strings move into a string array, and the collected array holds strings only.

const values: (string | number)[] = ["pen", 3, "book", 7];
const texts: string[] = [];
for (const value of values) {
  if (typeof value === "string") {
    texts.push(value);
  }
}
console.log(texts.length);
console.log(texts[0]);
console.log(texts[1]);

Truthiness handles the falsy members

The empty string and zero belong to this union and both are falsy values. The else branch logs them, so the output shows both falsy members handled instead of skipped.

const inputs: (string | number)[] = ["", "hi", 0, 5];
for (const input of inputs) {
  if (input) {
    console.log("truthy", input);
  } else {
    console.log("falsy", JSON.stringify(input));
  }
}

Narrowing undefined out of an array

Some elements of the array are undefined. The check pushes only the defined strings into the clean array.

const maybeTexts: (string | undefined)[] = ["ana", undefined, "luis", undefined, "mia"];
const cleanTexts: string[] = [];
for (const item of maybeTexts) {
  if (item !== undefined) {
    cleanTexts.push(item);
  }
}
console.log(cleanTexts.length);
console.log(cleanTexts[0]);
console.log(cleanTexts[2]);

Example

const rawValues: (string | number | null)[] = ["pen", 0, null, "", "box", 4];
const words: string[] = [];
const counts: number[] = [];
for (const value of rawValues) {
  if (typeof value === "string") {
    if (value) {
      words.push(value);
    }
  } else if (typeof value === "number") {
    counts.push(value);
  }
}
console.log(words.length);
console.log(words[0]);
console.log(words[1]);
console.log(counts.length);
console.log(counts[0]);
console.log(counts[1]);

Key points

  • A typeof check inside a loop narrows the current element in that branch.
  • Pushing narrowed elements into a typed array builds a collection of one member type.
  • Truthiness narrowing treats the empty string and zero as falsy members of their unions.
  • A falsy member goes to the else branch, so code handles it there.
  • Comparing an element against undefined narrows undefined out of the remaining branch.

In this example, typeof sorting keeps the number zero in the counts array, while the inner truthiness check drops the empty string from the words array.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท TypeScript Playground

Exercise

A value has type string and holds the empty string. What does a plain if (value) check do with it?