undefined

Types an uninitialised or missing value, distinct from a property marked optional with ?.

Signature
let value: string | undefined = undefined;
  • Added in TypeScript 2.0

Errors

With strictNullChecks on, using a possibly-undefined value is a compile error: "'value' is possibly 'undefined'."

Changelog

  • PHP 2.0undefined became usable as a type name; under strictNullChecks it is assignable only to undefined, void and any.
  • PHP 3.7?. and ?? short-circuit on undefined as well as null.
  • PHP 4.4exactOptionalPropertyTypes added: with it on, an optional property may be absent but may not be assigned undefined unless undefined is in its declared type.

undefined is what JavaScript gives you for a variable that was never assigned, a property that is not there, and an argument that was not passed. TypeScript names that value as a type.

Optional is not the same as "can be undefined"

These two declarations are different:

  • title?: string — the key may be absent from the object entirely.
  • title: string | undefined — the key must be present, but may hold undefined.

Reading either gives you string | undefined, so the distinction is invisible at the read site and very visible at the construction site: the second form forces you to write the key out. Use it when "I did not set this" and "I set this to nothing" are different states, or when you want Object.keys and spread merges to behave predictably.

exactOptionalPropertyTypes

By default title?: string also accepts an explicit undefined. Enable exactOptionalPropertyTypes (TypeScript 4.4) and ? means strictly "absent": assigning undefined is then rejected unless you widen the type to string | undefined. It is not part of strict, so you must opt in.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Distinguishing a settings field the user cleared from one they never touched
  • Typing the result of Array.prototype.find, which is T | undefined
  • Turning off implicit undefined on optional properties with exactOptionalPropertyTypes for API request bodies

Frequently asked questions

What is the difference between an optional property and one typed undefined?

`x?: T` allows the key to be missing; `x: T | undefined` requires the key to be present but lets it hold `undefined`. Both read as `T | undefined`, so the difference shows up when constructing the object, in `in` checks, in `Object.keys`, and in spread merges. Use the second form when "never set" and "explicitly cleared" are different states.

What does exactOptionalPropertyTypes do?

It makes `?` mean strictly "may be absent" — assigning `undefined` to an optional property becomes an error unless `undefined` is in its declared type. Added in TypeScript 4.4 and not included in `strict`, so you enable it explicitly. It prevents an explicit `undefined` from overwriting a default during an object spread.

How do I fix "Object is possibly 'undefined'"?

Narrow before use: `if (x !== undefined)`, a truthiness check, `x?.prop`, or `x ?? fallback`. For array `find` and map `get`, handle the miss explicitly rather than asserting. The non-null assertion `x!` compiles but performs no check, so reserve it for cases where you can prove the value is set.

More examples

Spread order and an explicit undefined

The first log shows `{ retries: undefined, verbose: 2 }`: spreading a key whose value is `undefined` still overwrites the default, because the key exists. After filtering, the second log shows `{ retries: 3, verbose: 2 }`. This is the concrete cost of treating `?` and `| undefined` as interchangeable, and the reason `exactOptionalPropertyTypes` exists.

Example · typescript
interface Options { retries?: number; verbose?: number }

const defaults: Options = { retries: 3, verbose: 0 };
const fromFlags = { retries: undefined, verbose: 2 };

// The explicit undefined wins — it is a present key.
const merged = { ...defaults, ...fromFlags };
console.log(merged);

// Dropping undefined keys first restores the intent.
const cleaned = Object.fromEntries(
  Object.entries(fromFlags).filter(([, v]) => v !== undefined)
);
console.log({ ...defaults, ...cleaned });
console.log(merged.retries ?? defaults.retries);

undefined from lookups and optional parameters

Prints `Ada`, `unknown`, `anonymous`, `undefined`. `fallback?: string` is itself `string | undefined` inside the body, which is why `??` is needed on the next line. The final log shows the raw `find` result — the value the type `T | undefined` is describing.

Example · typescript
const users = [
  { id: 1, name: "Ada" },
  { id: 2, name: "Grace" },
];

// find returns T | undefined under strictNullChecks
function nameOf(id: number, fallback?: string): string {
  const user = users.find((u) => u.id === id);
  if (user === undefined) return fallback ?? "unknown";
  return user.name;
}

console.log(nameOf(1));
console.log(nameOf(9));
console.log(nameOf(9, "anonymous"));
console.log(users.find((u) => u.id === 9));
// user.name without the guard: 'user' is possibly 'undefined'.

Discussion

  • Be the first to comment on this lesson.