TYPESCRIPT

TypeScript Required Type: Syntax, Use Cases, and Examples

The TypeScript required utility type is used to transform all optional properties of a type into required ones. This built-in utility is especially useful when you want to enforce strict object shapes and ensure that no properties are missing during runtime, even if the original type allowed them to be optional.

This guide explains how the required TypeScript type works, why it’s important, and how to use it effectively. It also covers edge cases, combining Required with other utility types, and clarifies confusion around the secondary concept of require in TypeScript imports.


What Is the TypeScript Required Type?

The Required utility type in TypeScript constructs a new type by setting all optional properties of an existing type to required. It's the opposite of the Partial utility, which makes all properties optional.

Here’s how Required<T> is defined under the hood:

type Required<T> = {
  [P in keyof T]-?: T[P];
};

This utility removes the optional flag (?) from every property, making them mandatory.


Syntax of Required TypeScript

The syntax is straightforward:

Required<Type>

Example:

type User = {
  id: number;
  name?: string;
  email?: string;
};

type CompleteUser = Required<User>;

The CompleteUser type is now:

ts
CopyEdit
{
  id: number;
  name: string;
  email: string;
}

All properties in CompleteUser are required, even those that were optional in User.


Why Use the TypeScript Required Type?

Using required TypeScript enforces object completeness. It’s useful in scenarios such as:

  • Validating that all form fields have been filled out
  • Ensuring configuration objects are fully populated
  • Passing fully populated data to external APIs
  • Transforming partial types into complete ones during runtime
  • Writing strict test cases with no missing fields

Rather than manually rewriting types with all fields marked as required, you can apply Required and let TypeScript do the work for you.


TypeScript Required Type Example: Validation Logic

Suppose you have a form input that starts with a partial type and gets validated over time. Once validated, you may want to ensure all fields are present before submitting the data.

type FormData = {
  name?: string;
  email?: string;
  age?: number;
};

type ValidForm = Required<FormData>;

With ValidForm, you're guaranteed that name, email, and age are all provided and properly typed.


TypeScript Required with Interfaces

Just like with regular object types, Required can be used with interfaces.

interface Product {
  id: string;
  name?: string;
  price?: number;
}

type FullProduct = Required<Product>;

Now FullProduct requires all three properties, including name and price, even though they were optional in the original interface.


TypeScript Deep Required

Like Partial, the built-in Required only affects the top-level properties. For deeply nested structures, you’ll need a custom recursive type to apply the transformation to all levels.

Here’s how to define a DeepRequired type:

type DeepRequired<T> = {
  [P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
};

Example:

type User = {
  profile?: {
    name?: string;
    age?: number;
  };
};

type FullyRequiredUser = DeepRequired<User>;

In FullyRequiredUser, both profile and its inner fields name and age are required. This is helpful when you need to sanitize and fully validate deeply nested input data.


Combining Required with Other Utility Types

You can combine Required with other utility types to model more specific scenarios.

Required + Partial

Suppose you want to make some properties optional but others mandatory:

type Settings = {
  theme?: string;
  language?: string;
  region?: string;
};

type LanguageRequired = Required<Pick<Settings, 'language'>> & Partial<Omit<Settings, 'language'>>;

This results in a type where language is required, but theme and region remain optional.

Required + Readonly

You can create a type that’s both fully required and immutable:

type UserSettings = {
  notifications?: boolean;
  darkMode?: boolean;
};

type FinalSettings = Readonly<Required<UserSettings>>;

This ensures all fields are present and cannot be modified after initialization.


Real-World Use Cases for Required TypeScript

Data Transformation

When working with data transformation pipelines (e.g., parsing JSON input or validating form data), you might start with a Partial version and progressively build up a Required version before saving or submitting it.

function finalizeForm(data: Partial<FormData>): Required<FormData> {
  // Validate and assign defaults if needed
  return {
    name: data.name ?? '',
    email: data.email ?? '',
    age: data.age ?? 18
  };
}

Here, you take a potentially incomplete object and ensure it conforms to the fully required structure before moving forward.

Strict Testing

When writing unit tests, you often want to ensure test objects are fully defined. Using Required helps catch any missing fields.

const mockUser: Required<User> = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com'
};

This protects you from accidentally omitting fields during test setup.


Required TypeScript vs require Import

A common point of confusion arises from the term require in JavaScript or TypeScript modules.

In older CommonJS or Node.js-based code, require() is used for importing modules:

const fs = require('fs');

In contrast, ES Modules and modern TypeScript use the import statement:

import fs from 'fs';

TypeScript import vs require

  • require() is dynamic and evaluates at runtime. It’s still used in legacy code or situations where imports must be conditionally loaded.
  • import is static and preferred in TypeScript for its better type support and tree-shaking benefits.

The required TypeScript type has no relation to require() function usage. The former is a compile-time type utility, while the latter is a runtime construct.


Editor Support and Type Safety

Using Required provides full IDE support:

  • Autocompletion for all required fields
  • Real-time error feedback for missing properties
  • Safer refactoring—if a property is renamed in the original type, dependent Required types will automatically reflect the change

These benefits help catch issues earlier and make code easier to maintain.


Limitations of the Required Utility

Although Required is powerful, it doesn’t modify nested properties. You’ll need a recursive utility like DeepRequired for that. Also, if the source type includes functions or special class behaviors, transforming everything to required might not always align with your needs.

Use it thoughtfully—overusing Required in places where flexibility is expected may lead to overly strict code that’s harder to extend or reuse.


Summary

The TypeScript required utility type lets you enforce completeness in object types by converting all optional fields into required ones. It’s particularly helpful for data validation, strict test mocks, full configuration enforcement, and ensuring predictable object structures across layers.

You can apply it to interfaces, combine it with Pick, Omit, or Readonly, and even extend it to nested structures using a custom DeepRequired type.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH

Reach your coding goals faster