- Abstract class
- Annotations
- Array
- Asserts
- Casting
- Class
- Conditional types
- Const
- Date object
- Decorators
- Default parameter
- Dictionary
- Enum
- Exclude type
- Extract type
- For loop
- forEach()
- Function
- Generics
- Index signature
- Infer
- Inheritance
- Interface
- Keyof type operator
- Let
- Map type
- Mixin
- Module
- Namespace
- Never
- Object type
- Omit type
- Operator
- Optional parameter
- Partial type
- Pick type
- Promise
- Property
- Readonly type
- Record type
- Required type
- Satisfies operator
- Tuples
- Type alias
- Type assertion
- Type guard
- Type narrowing
- typeof Type Operator
- Union
- Utility types
- Var
- Void
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.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.