CodeBlanks Logo Icon CodeBlanks

Literal discriminant

Learn to discriminate with literal fields.

Literal discriminant

The discriminant field's value is a literal type; each member carries its own unique literal value. A value like kind: "circle" tells TypeScript which member is present. Using literal values makes the narrowing precise and safe.

type Event =
  | { type: "click"; x: number; y: number }
  | { type: "scroll"; offset: number };

function handle(e: Event) {
  if (e.type === "click") {
    console.log(e.x, e.y);  // click member
  } else {
    console.log(e.offset);  // scroll member
  }
}

Narrowing with literal values

When the discriminant is a literal, TypeScript narrows the union with an equality check. The condition e.type === "click" reduces the Event union to only the click member; inside the condition e.x and e.y are safe to use.

function handle(e: Event) {
  if (e.type === "click") {
    e.x;  // number (click member)
    e.y;  // number (click member)
  }
  // Here e.x is not accessible: e is the full Event again
}

Practice Handle events with a literal discriminant

Define the Event discriminated union type: "click" (x: number, y: number) and "scroll" (offset: number) members, with a type discriminant field. Write a handle(e: Event): string function. If e.type === "click", return `click at ${e.x},${e.y}`; otherwise return `scroll ${e.offset}`. Print results via console.log(handle({ type: "click", x: 10, y: 20 })) and console.log(handle({ type: "scroll", offset: 5 })).

Starter code

index.ts
// Event discriminated union türünü tanımla (type discriminant, click ve scroll üyeleri)

// handle(e: Event): string fonksiyonunu type kontrolüyle yaz

// click ve scroll olaylarının sonuçlarını yazdır

Sample solution

index.ts
type Event =
  | { type: "click"; x: number; y: number }
  | { type: "scroll"; offset: number };

function handle(e: Event): string {
  if (e.type === "click") {
    return `click at ${e.x},${e.y}`;
  }
  return `scroll ${e.offset}`;
}

console.log(handle({ type: "click", x: 10, y: 20 }));
console.log(handle({ type: "scroll", offset: 5 }));

Expected output

click at 10,20
scroll 5

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What type should the discriminant field's value be?

  • Any number
  • An optional value
  • A different literal value in each member Correct answer
  • The same value in each member

Explanation: The discriminant field takes a different literal value in each member; this lets TypeScript narrow the union to a single member with an equality check.

2 Narrowing with a literal discriminant

Question
type Event =
  | { type: "click"; x: number; y: number }
  | { type: "scroll"; offset: number };

function handle(e: Event) {
  if (e.type === ____) {
    return e.x + e.y;
  }
  return e.offset;
}
Answer
type Event =
  | { type: "click"; x: number; y: number }
  | { type: "scroll"; offset: number };

function handle(e: Event) {
  if (e.type === "click") {
    return e.x + e.y;
  }
  return e.offset;
}

Explanation: Checking the discriminant literal "click" narrows the union to the click member; inside the condition e.x and e.y are safe to use.

3 Literal discriminant parts

Term Meaning
Literal değer unique in each member
e.type === "click" narrows to click member
Discriminant alan of literal type
Eşitlik kontrolü narrowing method

All lessons in Advanced