skip to content

In TypeScript, what are `Required<{ a?: number }>` and `Required<{ b: number | undefined }>`, and why do the two results differ?

level: middleimportance: nice to knowfreq 30%

answer

  1. it removes a marker, not a type member
  2. no marker present, nothing to remove
  3. presence and value are separate axes
  4. optional-to-required also drops undefined
  5. required does not mean defined

basics

~20 s

Required<{ a?: number }> is { a: number } and Required<{ b: number | undefined }> is unchanged at { b: number | undefined }. Required removes the optional marker, and only where it removes one does it also drop undefined from that property's type.

solid answer

~40 s

`Required<T>` strips the optional marker from every property. When it strips one, it also removes `undefined` from that property's type, so `a?: number` becomes `a: number`. The second case has no optional marker to strip — `b` was declared as a required property whose type happens to include `undefined` — so `Required` leaves it exactly as `b: number | undefined`. The lesson is that presence and non-undefined-ness are two separate axes in TypeScript's model: `Required<T>` guarantees the property is there, not that reading it gives you a defined value. If you need the second guarantee you have to change the property type itself, not its optionality.

code

typescript · 12 lines
typescript
type X = { a?: number; b: number | undefined };

type Y = Required<X>;
// Y is { a: number; b: number | undefined }

const ok: Y = { a: 1, b: undefined };

// @ts-expect-error a is now required and can no longer be undefined
const bad: Y = { a: undefined, b: 1 };

// @ts-expect-error b must still be present even though it may hold undefined
const missing: Y = { a: 1 };

go deeper

for a junior

Know that Required<T> is the opposite of Partial<T>: it makes every property mandatory. Being able to state that much, plus that types are erased, is enough at this level.

for a middle

Explain that Required removes the optional marker and drops undefined only where it removed one, so a property declared with an explicit | undefined comes through untouched.

for a senior

Show why the distinction matters downstream — a present-but-undefined key is visible to in, to key enumeration and to a spread — and treat a stray | undefined in a declaration as a modelling defect to fix rather than to transform around.

for a principal

Own the convention for how optionality is expressed across the codebase, since a mix of optional markers and explicit undefined unions makes every generic transform behave inconsistently and makes strictness flags harder to adopt later.

## The definition, and what it actually does ```typescript type Required<T> = { [P in keyof T]-?: T[P] }; ``` The `-?` says "remove the optional marker". What is easy to miss is that removing optionality also removes `undefined` from the resulting property type — but only for a property that *was* optional. That conditional behaviour is exactly what produces the two different answers. ## Case one: the property was optional ```typescript type A = { a?: number }; type RA = Required<A>; // { a: number } ``` Under `strictNullChecks`, `a?: number` means the property may be absent, and reading it gives `number | undefined`. `Required` removes the marker and, because it removed one, removes `undefined` too. The result is a property that must be present and holds a number. This is the case people expect, and it is why `Required<T>` is the natural output type of a "defaults have been applied" step. ## Case two: the property was already required ```typescript type B = { b: number | undefined }; type RB = Required<B>; // { b: number | undefined } ``` Here `b` is a required property. The object must have the key, and the value may be `number` or `undefined`. There is no optional marker to remove, so `-?` is a no-op and the declared type is copied through unchanged. `Required<B>` and `B` are the same type. ## The distinction being tested TypeScript models two separate things that everyday speech runs together: 1. **Presence** — must the key be on the object? Controlled by `?`. 2. **Value** — can the value be `undefined`? Controlled by the property's type. ```typescript type X = { a?: number; b: number | undefined }; const ok1: X = { b: undefined }; // a may be absent const ok2: X = { a: 1, b: undefined }; // b must be present, may be undefined const bad: X = { a: 1 }; // error: b is missing entirely ``` The `b: undefined` distinction matters in practice: `"b" in obj` is true for `ok2` and a `for...in` loop or `Object.keys` will list it, which is why a spread of such an object copies the key over a real value. So "required" and "never undefined" are genuinely different guarantees, and `Required<T>` only delivers the first one — plus the second as a side effect where it had an optional marker to remove. ## Getting the guarantee you actually wanted If you need "present and definitely not undefined" across a type whose properties were declared with an explicit `| undefined`, `Required<T>` is not the tool. You have to transform the property *types*, which means either fixing the declarations (drop the gratuitous `| undefined`) or writing a mapped type whose body strips undefined from each property type — `NonNullable` is the built-in that does the stripping for a single type. In most codebases the right answer is the first one. A property declared `b: number | undefined` rather than `b?: number` is usually a modelling slip; the two are close in meaning but not the same, and the explicit-union form is the one that forces every caller to write the key out. Under `exactOptionalPropertyTypes` the difference between the two declarations becomes sharper still, because an optional property then no longer silently accepts an explicit `undefined`. ## How this shows up in interviews Usually as a two-line snippet with "what is the resulting type?" — a check on whether you know that `Required<T>` is a modifier operation, not a value-level cleanup. A candidate who says "it makes everything non-optional and non-undefined" is half right and will be caught by the second case.

  • Is `a?: number` the same as `a: number | undefined`?
    No. The first says the key may be absent; the second says the key must be present and its value may be undefined, so omitting it is an error. They also behave differently at run time in ways the types reflect: an explicitly present key with an undefined value is visible to `in` and to `Object.keys`, and a spread copies it. Under `exactOptionalPropertyTypes` the two declarations diverge further, since an optional property then rejects an explicitly written undefined.
  • How would you build a type where every property is present and none can be undefined?
    Map over the keys and transform the property types as well as the modifiers, using `NonNullable` on each property type — `Required<T>` alone only touches the marker. In most codebases, though, the better fix is upstream: if a property was declared `| undefined` when it meant optional, correct the declaration rather than papering over it with another transform.

saying these in an interview costs you the question

  • Says Required removes undefined from every property type
  • Treats a? : number and a: number | undefined as identical
  • Thinks Required<T> validates anything at run time
  • Expects Required to reach into nested object properties
  • Claims a required property can never hold undefined

context