DEV Community

Kyungsu Kang
Kyungsu Kang

Posted on

4 3 3 3 3

TypeScript Deep Dive: Mastering DeepStrictOmit, DeepStrictPick, and DeepStrictAssert

TypeScript Deep Dive: Mastering DeepStrictOmit, DeepStrictPick, and DeepStrictAssert

Introduction

When building robust TypeScript applications, maintaining type safety across deeply nested objects can be a challenge. Enter DeepStrictOmit, DeepStrictPick, and DeepStrictAssert — powerful utilities to navigate, manipulate, and validate deeply nested structures while preserving TypeScript’s strong typing capabilities.

In this article, we’ll explore these utilities in depth, showcasing their use cases and providing practical examples to help you master them. By the end, you’ll be equipped to handle even the most complex TypeScript structures with ease.


Why These Utilities Matter

In real-world applications, we often encounter deeply nested data structures that require precise transformations or validations. Common challenges include:

  • Omitting keys at various depths
  • Picking specific keys from deeply nested objects
  • Validating the presence of keys dynamically

Traditional approaches can be cumbersome, error-prone, or lose type safety. That’s where DeepStrictOmit, DeepStrictPick, and DeepStrictAssert shine.


What is DeepStrictOmit?

DeepStrictOmit removes specific keys from deeply nested objects, ensuring type safety at every level. It extends the functionality of TypeScript’s built-in Omit to handle complex structures, including arrays.

Example

import { DeepStrictOmit } from "./types/DeepStrictOmit";

type Example = {
  id: string;
  details: {
    name: string;
    address: {
      city: string;
      zip: string;
    };
  };
};

type Result = DeepStrictOmit<Example, "details.address.city">;
// Result: {
//   id: string;
//   details: {
//     name: string;
//     address: {
//       zip: string;
//     };
//   };
// }
Enter fullscreen mode Exit fullscreen mode

Example image of DeepStrictOmit type

Key Features

  • Omits properties at any depth using dot notation (e.g., details.address.city).
  • Handles arrays seamlessly with [*] notation.

What is DeepStrictPick?

DeepStrictPick is the counterpart to DeepStrictOmit. It allows you to extract specific keys from deeply nested objects while maintaining precise type definitions.

Example

import { DeepStrictPick } from "./types/DeepStrictPick";

type Example = {
  a: number;
  b: number;
  c: {
    d: string;
    e: string;
    f: {
      g: boolean;
      h: boolean;
    }[];
  }[];
};

type Result = DeepStrictPick<Example, "c[*].f[*].g">;
// Result: {
//   c: {
//     f: {
//       g: boolean;
//     }[];
//   }[];
// }
Enter fullscreen mode Exit fullscreen mode

Key Features

  • Picks properties at any depth using dot and array notation.
  • Provides precise typing for extracted keys.

Introducing DeepStrictAssert

DeepStrictAssert validates that a given key exists within a nested object at runtime, while retaining its type safety. It’s particularly useful for dynamic validations in API responses or user inputs.

Implementation

import { DeepStrictAssert } from "./types/DeepStrictAssert";

const deepStrictAssert =
  <T extends object>(input: T) =>
  <K extends DeepStrictObjectKeys<T>>(key: K): DeepStrictPick<T, K> => {
    const keys = key.split(/(?:\[\*\])?\./g).filter(Boolean);

    const traverse = (input: any, keys: string[]): any => {
      const [first, ...rest] = keys;
      if (input instanceof Array) {
        return input.map(element =>
          typeof element[first] === "object" && element[first] !== null
            ? { [first]: traverse(element[first], rest) }
            : { [first]: element[first] }
        );
      } else {
        if (typeof input[first] === "object" && input[first] !== null) {
          return { [first]: traverse(input[first], rest) };
        }
        return { [first]: input[first] };
      }
    };

    return traverse(input, keys) as DeepStrictPick<T, K>;
  };
Enter fullscreen mode Exit fullscreen mode

Example Usage

interface Example {
  a: number;
  b: number;
  c: {
    d: string;
    e: string;
    f: {
      g: boolean;
      h: boolean;
    }[];
  }[];
}

const data: Example = {
  a: 1,
  b: 2,
  c: [
    {
      d: "hello",
      e: "world",
      f: [{ g: true, h: false }],
    },
  ],
};

const result = deepStrictAssert(data)("c[*].f[*].g");
console.log(result);
// Output: { c: [{ f: [{ g: true }] }] }
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

  1. API Responses:

    • Extract or omit specific fields from complex API responses to shape the data as needed.
  2. Form Validation:

    • Validate deeply nested form inputs dynamically while keeping type safety.
  3. Data Transformation:

    • Transform nested structures in databases or data pipelines with precision.

Conclusion

DeepStrictOmit, DeepStrictPick, and DeepStrictAssert are game-changers for managing complex TypeScript types. They bring unparalleled precision, type safety, and ease of use to deeply nested data structures. Whether you’re working on APIs, forms, or data pipelines, these utilities will undoubtedly enhance your TypeScript toolkit.

This project and library are relatively new, so your understanding and support are greatly appreciated. Contributions, feedback, and bug reports are warmly welcomed to help us refine and improve these utilities further.

Ready to take your TypeScript skills to the next level? Try them out in your next project and experience the difference firsthand!

Heroku

Deploy with ease. Manage efficiently. Scale faster.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay