Typescript - Tips & Tricks - Conditional Type

In some cases, we need to detect if an object/type has specific properties or characteristics. Let me...

#typescript #webdev
Luca Del Puppo Luca Del Puppo
Article Series · Part 17 of 21 TypeScript - Tips & Tricks
View full series (21)
  1. #16 Previous
    Type Guard
  2. #17 Reading now
    Conditional Type
  3. #18 Up next
    infer keyword
Browse all 21 parts in this series
  1. #1 typeof
  2. #2 Literal Types
  3. #3 keyof
  4. #4 Union and Intersection
  5. #5 Overloaded Functions
  6. #6 this parameter
  7. #7 any vs. unknown
  8. #8 Optional modifier
  9. #9 Index Signature
  10. #10 readonly modifier
  11. #11 Readonly Array
  12. #12 Tuple
  13. #13 Non-null assertion operator
  14. #14 Never type
  15. #15 Assert Function
  16. #16 Type Guard
  17. #17 Conditional Type Current
  18. #18 infer keyword
  19. #19 Mapped Types
  20. #20 Advanced Types
  21. #21 Rest Parameters & Rest Arguments

In some cases, we need to detect if an object/type has specific properties or characteristics. Let me show you a simple case

type TypeName<T> =
    T extends string ? "string" :
    T extends number ? "number" :
    T extends bigint ? "bigint" :
    T extends boolean ? "boolean" :
    T extends undefined ? "undefined" :
    T extends symbol ? "symbol" :
    T extends Function ? "function" :
    T extends null ? "null" :
    "object";

const typeName = <T>(obj: T): TypeName<T> => {
  if (obj === null) return "null" as TypeName<T>;
  return typeof obj as TypeName<T>;
};

const stringType = typeName('string'); // "string"
const numberType = typeName(10); // "number"
const bigIntType = typeName(10n); // "bigint"
const booleanType = typeName(true); // "boolean"
const undefinedType = typeName(undefined); // "undefined"
const symbolType = typeName(Symbol()); // "symbol"
const functionType = typeName(() => 'result'); // "function"
const nullType = typeName(null); // "null"
const objectType = typeName({ name: 'name'}); // "object"

In this example, we return the type of the parameter as a string, but I want to focus on the TypeName type. This type as you can see, returns the values based on some conditions. In this case, the conditions are based on the parameter’s type, but my goal is to show you that you could check if a type respects some conditions or not and act accordingly. This feature is called Conditional Types. To show you the power of this feature here a funny example found in the net :)

type SnackBars = {
  name: "Short Chocolate Bars";
  amount: 4;
  candy: true;
};

type Gumballs = {
  name: "Gooey Gumballs";
  color: "green" | "purples";
  candy: true;
};

type Apples = {
  name: "Apples";
  candy: true;
};

type Cookies = {
  name: "Cookies";
  candy: true;
  peanuts: true;
};

type SnickersBar = {
  name: "Snickers Bar";
  candy: true;
  peanuts: true;
};

type Toothpaste = {
  name: "Toothpaste";
  minty: true;
  trick: true;
};

type Pencil = {
  name: "Pencil";
  trick: true;
};

type HalloweenTricksAndSweets =
  | SnackBars
  | Gumballs
  | Apples
  | SnickersBar
  | Cookies
  | Toothpaste
  | Pencil;

type AllCandies<T> = T extends { candy: true } ? T : never;
type AllTricks<T> = T extends { trick: true } ? T : never;
type AllCandiesWithoutPeanuts<T> = T extends { candy: true } ? (T extends { peanuts: true } ? never : T) : never;

type Candies = AllCandies<HalloweenTricksAndSweets>; // SnackBars | Gumballs | Apples | SnickersBar | Cookies
type Tricks = AllTricks<HalloweenTricksAndSweets>; // Toothpaste | Pencil
type CandiesWithoutPeanuts = AllCandiesWithoutPeanuts<HalloweenTricksAndSweets>; // SnackBars | Gumballs | Apples

In this example, you can see how the AllCandies type creates a new type (Candies) composed of all the HalloweenTricksAndSweets that contain the candy property with the true value. The AllTricks type creates a new type (Tricks) composed of all the HalloweenTricksAndSweets that contain the trick property with the true value. The last case AllCandiesWithoutPeanuts is interesting: we get all the candies that don’t contain the peanuts property with the true value. I think this funny example can express best the potential of the Conditional Type, and it can help you to understand better all the benefits it can lead to.

It’s all for today. I hope this feature will help you in the future as it helped me in some cases.

See you soon Guys!

Luca Del Puppo

Written by Luca Del Puppo

Run, Code & Learn

AI Native Engineer at Nearform based in Povegliano (TV), Italy. Google Developer Expert in Web Technologies, GitKraken Ambassador, and Codemotion Ambassador.