Utility type required in TypeScript
Required? from every optional property in T, making all of them required at compile time.
Theory
TL;DR
- Think of a form where all fields were optional, then someone stamped "fill in everything" on each one
- Main difference: removes
?from each property but keeps the type (string | undefineddoes NOT becomestring | undefined- it becomes juststring) - Use after validation when you know all fields are present; keep
Partial<T>while building the object - Compile-time only - no runtime effect
- Opposite of
Partial<T>
Quick example
interface User {
name: string;
age?: number; // optional
}
type StrictUser = Required<User>;
const user: StrictUser = { name: "Alice", age: 30 }; // works
// const bad: StrictUser = { name: "Bob" }; // Error: age is missingStrictUser now demands both name and age. Skip either one and TypeScript complains immediately.
Key difference
Required<T> only removes the ? modifier - it does not keep undefined in the type. So age?: number becomes age: number, not age: number | undefined. That matters when you write functions expecting a guaranteed value and want TypeScript to catch omissions at compile time, not at runtime.
When to use
- Data collected as
Partial<T>, then validated: useRequired<T>as the return type of your validation function - API response after a successful request: you know the shape is complete
- React component props with all defaults applied: pass
Required<Props>to child components - Generating mock data: avoids unexpected
undefinedcrashes in tests - After a type guard confirmed all fields exist:
data is Required<FormData>reads cleanly
How the compiler handles this
TypeScript maps over every property descriptor in T. For each one marked as optional, it rewrites the descriptor to required. Under the hood this is a mapped type: { [K in keyof T]-?: T[K] }. The -? syntax strips the optional modifier. No JavaScript is emitted - purely a compile-time transformation.
Common mistakes
1. Expecting runtime enforcement
// Required<T> does NOT check values at runtime
const data = JSON.parse(response) as Required<User>; // bypasses all checksTypeScript trusts the cast. Pair Required<T> with an actual type guard or a schema validator like Zod if you need runtime safety.
2. Thinking it handles nested optionals
The shallow behavior catches almost everyone the first time. You apply Required<T> expecting full coverage, then spend an hour debugging undefined three levels deep in a config object.
type Nested = Required<{ a?: { b?: string } }>;
// Result: { a: { b?: string } }
// a is required, but b inside is still optionalFor deep nesting, write a recursive type:
type DeepRequired<T> = T extends object
? { [K in keyof T]-?: DeepRequired<T[K]> }
: T;3. Applying it to union types
type Bad = Required<string | { a?: number }>;
// Resolves unexpectedly - avoid Required on union types directlyIf your type is a union, apply Required to each member separately or use Extract first.
4. Using it on primitives
Required<string> returns string unchanged. There is nothing to strip.
Real-world usage
- React form handler:
validateForm(data: FormData): data is Required<FormData>- type guard after checking all fields - Express middleware:
Request<{}, {}, Required<CreateUserBody>>after body validation - React Query:
Required<Omit<Response, 'data'>>on the success path - Zod:
z.infer<typeof schema> & Required<PartialFields>for partial schemas - TanStack Table: column def merging with
Required<Partial<ColumnDef>>
Follow-up questions
Q: What is the type of Required<{ a?: string }>?
A: { a: string }. The ? is removed and the type stays string, not string | undefined.
Q: Does Required<T> affect nested objects?
A: No. It only removes ? from top-level properties. Nested optional fields stay optional. Use a custom DeepRequired<T> for that.
Q: What is the difference between Required<T> and Omit<T, never>?
A: Same structural result, but Required<T> is the semantic choice. Omit<T, never> is a workaround and fails on non-object types.
Q: How do you make Required apply only to specific keys?
A: type RequiredSpecific<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>. This targets only the keys you name, leaving the rest untouched.
Q: Why does -? appear in mapped types?
A: It is a modifier syntax. +? adds the optional flag, -? strips it. Required<T> uses { [K in keyof T]-?: T[K] } internally.
Examples
Basic: making optional fields required
interface Product {
id: number;
name: string;
description?: string;
price?: number;
}
type FullProduct = Required<Product>;
const item: FullProduct = {
id: 1,
name: "Keyboard",
description: "Mechanical", // now required
price: 99, // now required
};
// const broken: FullProduct = { id: 1, name: "Mouse" }; // Error: missing fieldsBefore Required<T>, you could create a Product without description or price. After, TypeScript blocks it at the type level.
Intermediate: form validation with a type guard
interface FormData {
email: string;
phone?: string;
address?: string;
}
function validateForm(data: FormData): data is Required<FormData> {
return !!data.phone && !!data.address;
}
function submitUser(formData: FormData) {
if (validateForm(formData)) {
// TypeScript knows all fields are present inside this block
console.log(`${formData.email} - ${formData.phone} - ${formData.address}`);
}
}
const data: FormData = {
email: "user@example.com",
phone: "555-1234",
address: "10 Main St",
};
submitUser(data);The type guard data is Required<FormData> narrows the type inside the if block. No casting needed. This pattern appears often in Next.js API routes after collecting and checking form input.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.