Urgent.News

What's breaking now, across thousands of outlets.

Tech

Write your custom generic utility in TypeScript

I recently found myself writing the same kind of TypeScript type transformation in a few different places. Hello, I'm Vikash Kumar . I had an existing type where most properties were required, but for one particular use case, I wanted some of them to become optional. At first, I was just writing the transformation inline. Then I realized: Why not turn the pattern into a reusable utility? So I…

I recently discovered that I was writing the same TypeScript type transformation in multiple places. My name is Vikash Kumar. Initially, I was just writing the transformation inline. However, I soon realized that this pattern could be turned into a reusable utility. So, I created the following code:

export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

This simple utility has turned out to be surprisingly useful. Let's consider a configuration type:

type Config = {

name: string;

version: string;

description: string;

};

Typically, TypeScript expects all three properties. However, in a specific function, the description might be optional. In such cases, we could create a new type manually:

type PartialConfig = {

name: string;

version: string;

description?: string;

};

While this works, it results in duplicated type definitions. As the original type grows larger, this duplication becomes increasingly annoying. That's where the Optional utility comes in handy.

By using the Optional utility, we can simplify the process:

type PartialConfig = Optional<Config, 'description'>;

Now, TypeScript understands that in the PartialConfig type, the name and version properties remain required, while the description becomes optional. No duplicate type definitions are needed, and there's no manual rewriting involved.

Under the hood, the Optional utility combines three TypeScript utilities: Omit, Pick, and Partial. Let's break it down:

1. Pick<T, K> selects the properties we want to keep. For example:

Pick<Config, 'description'> becomes { description: string; }

2. Partial<Pick<T, K>> makes the selected properties optional:

Partial<Pick<Config, 'description'>> becomes { description?: string; }

3. Omit<T, K> keeps everything except the properties we want to exclude:

Omit<Config, 'description'> becomes { name: string; version: string; }

Combining these three utilities, we get:

Omit<Config, 'description'> & Partial<Pick<Config, 'description'>> which simplifies to { name: string; version: string; description?: string; }

This utility proves particularly useful when working with APIs, configuration objects, constructors, and update functions. For instance, consider an update function for a User type:

type User = {

id: string;

name: string;

email: string;

role: 'admin' | 'user';

};

When updating a user, we might not want to require every property. However, we still want the id to be required:

type UserUpdate = Optional<Pick<User, 'id' | 'name' | 'email' | 'role'>, 'name' | 'email' | 'role'>;

As a result, the UserUpdate type is now defined as:

{ id: string; role: 'admin' | 'user'; }

This concise and reusable Optional utility saves time and effort by eliminating the need for manual type duplication and rewriting.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

More from Monday 24 August →