Skip to Content
Narrow a Union With typeof and in
Beginner
0 likes
Tutorials

Narrow a Union With typeof and in

Use typeof, in and Array.isArray on three real unions, and avoid the two mistakes that stop narrowing from working. After this, you know which check fits which union.

A union is only useful once you can find out which member you have. This page covers the two checks you will use most, typeof for simple values and in for objects, with three real cases and the two mistakes that make narrowing fail.

What typeof can tell apart

typeof returns one of eight words.

typeof givesUse it for
"string", "number", "boolean", "bigint", "symbol"plain values
"undefined"a missing value
"function"a callback or a function option
"object"objects, arrays and null (not helpful on its own)

Case 1: a string or a list of strings

An option that accepts one tag or several.

function toList(tags: string | string[]): string[] {
  if (typeof tags === "string") {
    return [tags];
  }
  return tags;
}

console.log(toList("new"));
console.log(toList(["new", "sale"]));
[ 'new' ]
[ 'new', 'sale' ]

Inside the if, tags is a string. After it, the only member left is string[]. No cast was needed.

Case 2: a value or a function that produces it

function resolve(value: string | (() => string)): string {
  if (typeof value === "function") {
    return value();
  }
  return value;
}

console.log(resolve("fixed"));
console.log(resolve(() => "computed"));
fixed
computed

typeof value === "function" is true only for the function member, so the call value() is allowed inside the block.

Case 3: objects with different keys, using in

typeof says "object" for all of these, so it cannot help. Ask whether a property is there.

type Failure = { error: string };
type Success = { items: string[] };

function show(result: Success | Failure): string {
  if ("error" in result) {
    return "Failed: " + result.error;
  }
  return result.items.length + " items";
}

console.log(show({ items: ["a", "b"] }));
console.log(show({ error: "timeout" }));
2 items
Failed: timeout

"error" in result is true only for a Failure, so the compiler knows the rest is a Success.

Mistake 1: using in with a key both members have

type Customer = { name: string; id: number };
type Guest = { name: string; visits: number };

function describe(person: Customer | Guest): string {
  if ("name" in person) {
    return "Customer ID " + person.id;
  }
  return "Guest";
}
both.ts(6,36): error TS2339: Property 'id' does not exist on type 'Customer | Guest'.
  Property 'id' does not exist on type 'Guest'.

Both types have name, so the check proves nothing, and the compiler does not narrow. Pick a key that exists in only one member, like "id" in person. If no such key exists, the types are too alike for in, and you will want a field that names the kind, like kind: "customer".

Mistake 2: using typeof to tell an array from an object

console.log(typeof [], typeof {}, typeof null);
console.log(Array.isArray([]), Array.isArray({}));
object object object
true false

All three typeof results are "object". To check for an array, use Array.isArray. TypeScript understands it, and narrows to an array type inside the block.

function first(input: string[] | { name: string }): string {
  if (Array.isArray(input)) {
    return input[0] ?? "empty";
  }
  return input.name;
}

console.log(first(["a", "b"]), first([]), first({ name: "Ana" }));
a empty Ana

⚠ Warning: Narrowing only lasts inside the block you checked. Move the use of the value outside that block and the compiler forgets what you proved.

Which check to use

  • Simple values and functions: typeof.
  • Arrays: Array.isArray.
  • Objects that differ by a key: in, with a key only one member has.
  • null: compare with === null, never with typeof.

Related course: TypeScript for Beginners.

About

Use typeof, in and Array.isArray on three real unions, and avoid the two mistakes that stop narrowing from working. After this, you know which check fits which union.

Responsible
Christopher R
Last Update
10/14/2026
Reading Time
3 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.