How to deal with optional params in your interfaces

Discriminated Unions

$ buyProduct
· vipCode?
VIPUser
User

Discriminated Unions

Kacper Walczak · 08-11-2023

  • Learn how to deal with optional properties in typescript.

Problem

We have two types of users: VIP and regular users. VIP users have a vipCode property, but regular users don't.

We can sell product to a VIP user with discount based on their vipCode, but we can't sell product to a regular user with discount.

Most likely we will have an interface for User with optional vipCode property, but it's not a good solution, because we can't use it to distinguish between VIP and regular users.

TS compiler will yell at you if you try to access vipCode property on a regular user. TS doesn't know that you have checked the type of user before accessing vipCode property.

type User = {
    type: "default" | "VIP";
    id: string;
    vipCode?: string;
};
 
function buyProduct(productID: string, buyer: User) {
    switch (buyer.type) {
        case "default":
            return sales.order({
                what: productID,
                buyer: buyer.id
            });
        case "VIP":
            return sales.order({
                what: productID,
                buyer: buyer.id,
                vipCode: buyer.vipCode // can be undefined here, so it's an error for the compiler
            });
    }
}

Solution

The solution is to use two types: User and VipUser - both have only one type - what allows TS to distinguish between them.

It is called Discriminated Unions in Typescript.

Visit docs to learn more at Discriminated Unions - typescriptlang.org (opens in a new tab).

type User = {
    type: "default";
    id: string;
};
 
type VipUser = {
    type: "VIP";
    id: string;
    vipCode: string;
};
 
type Buyer =
    | User
    | VipUser;
 
function buyProduct(productID: string, buyer: Buyer) {
    switch (buyer.type) {
        case "default":
            return sales.order({
                what: productID,
                buyer: buyer.id
            });
        case "VIP":
            return sales.order({
                what: productID,
                buyer: buyer.id,
                vipCode: buyer.vipCode
            });
    }
}

This way we can properly distinguish between VIP and regular users. That's all.

READ

Latest readings

  • Readings are sites which will help you with detailed

  • information about given topic. Read latest ones from Learn.

AI

06-03-2026

Local Voice Assistant with Ollama
  • Build your own local voice assistant powered by Ollama.

AI

06-03-2026

AI YouTube Thumbnail Generator
  • Generate YouTube thumbnails with FastAPI and Ollama.

Architecture

05-09-2024

Graph DB usage comparison
  • Compare Neo4j and Tigergraph databases, which is easier to work with, etc.