Question

Understanding Type 'string | undefined' Is Not Assignable to Type 'string' in TypeScript

Question

In TypeScript, if I make properties in an interface optional and then assign one of those properties to a variable typed as string, I get an error.

For example:

interface Person {
  name?: string;
  age?: string;
  gender?: string;
  occupation?: string;
}

function getPerson(): Person {
  const person: Person = { name: "John" };
  return person;
}

const person: Person = getPerson();
const name1: string = person.name; // Error here

TypeScript reports:

TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.

Why does this happen, and what are the correct ways to handle this situation safely?

Short Answer

By the end of this page, you will understand why optional properties in TypeScript become unions like string | undefined, why that cannot be assigned directly to a plain string, and how to fix it safely using checks, default values, optional chaining, nullish coalescing, and type assertions when appropriate.

Concept

In TypeScript, an optional property like:

name?: string;

means the property may or may not exist. Because of that, when you read it, TypeScript treats its type as:

string | undefined

That is a union type: the value could be a string, or it could be undefined.

A variable declared as plain string must always contain a real string value. Since undefined is a possible value for person.name, TypeScript prevents this assignment:

const name1: string = person.name;

This matters because TypeScript is trying to protect you from runtime bugs. If person.name is missing and your code assumes it is always a string, string operations like .toUpperCase() could fail.

This behavior is especially important when strictNullChecks is enabled, which is common in modern TypeScript projects. With strict null checking, null and undefined are treated as separate types and must be handled deliberately.

So the real issue is not just the syntax of optional properties. The deeper concept is type safety around missing values.

Mental Model

Think of an optional property like a box that may be empty.

  • string means: this box definitely contains a string.
  • string | undefined means: this box might contain a string, or it might be empty.

TypeScript does not let you hand a possibly empty box to code that expects a guaranteed string.

You must do one of these:

  • Check the box first
  • Provide a fallback value
  • Tell TypeScript you are certain it is not empty

That is exactly what the common solutions do.

Take Quiz

Syntax and Examples

Core idea

Optional properties use ?:

interface Person {
  name?: string;
}

Reading person.name gives:

string | undefined

Safe solution 1: check before using

interface Person {
  name?: string;
}

const person: Person = { name: "John" };

let name1: string;

if (person.name !== undefined) {
  name1 = person.name;
}

This works because inside the if block, TypeScript narrows the type from string | undefined to string.

Safe solution 2: provide a default value

interface Person {
  name?: string;
}

const person: Person = {};
const name1: string = person.name ?? "Anonymous";

If person.name is undefined, "Anonymous" is used instead.

Safe solution 3: allow the variable to also be undefined

interface Person {
  name?: string;
}

const person: Person = {};
const name1: string | undefined = person.name;

This is correct if the variable is also allowed to be missing.

Possible but risky: non-null assertion

interface Person {
  name?: string;
}

const person: Person = { name: "John" };
const name1: string = person.name!;

The ! tells TypeScript: "I know this is not undefined."

Use this only when you are truly certain. If the value is actually missing at runtime, your program can still fail.

Another option: make the property required

interface Person {
  name: string;
}

If every Person must always have a name, then the property should not be optional in the first place.

Step by Step Execution

Consider this example:

interface Person {
  name?: string;
}

const person: Person = {};
const name1: string = person.name ?? "Anonymous";
console.log(name1);

Step by step

  1. Person defines name as optional.
  2. That means reading person.name gives a value of type string | undefined.
  3. person is created as an empty object, so name is missing.
  4. person.name evaluates to undefined.
  5. The nullish coalescing operator ?? checks whether the left side is null or undefined.
  6. Because person.name is undefined, TypeScript and JavaScript use the fallback value "Anonymous".
  7. name1 receives a guaranteed string.
  8. console.log(name1) prints:
Anonymous

Compare with the broken version

interface Person {
  name?: string;
}

const person: Person = {};
const name1: string = person.name;

Here, TypeScript blocks the assignment because person.name might be undefined.

Real World Use Cases

This pattern appears constantly in real TypeScript code.

API responses

An API may omit fields:

interface UserResponse {
  displayName?: string;
}

You often need:

const displayName = user.displayName ?? "Guest";

Form input

Some fields may be optional until the user fills them in.

interface SignupForm {
  email?: string;
}

Before submitting, you validate that required values exist.

Configuration objects

App settings often allow optional overrides:

interface Config {
  theme?: string;
}

const theme = config.theme ?? "light";

Database records

Some columns may be nullable or missing depending on the query or migration state.

UI rendering

Frontend components often display fallback text:

const label = person.name ?? "No name provided";
Take Quiz

Real Codebase Usage

In real projects, developers usually handle optional values with a few standard patterns.

Guard clauses

function printName(person: Person): void {
  if (!person.name) {
    console.log("Missing name");
    return;
  }

  console.log(person.name.toUpperCase());
}

This exits early if the value is missing.

Default values

const name = person.name ?? "Anonymous";

This is common in UI code, configuration loading, and API mapping.

Validation before use

function savePerson(person: Person): void {
  if (person.name === undefined) {
    throw new Error("name is required");
  }

  const normalized = person.name.trim();
  console.log(normalized);
}

Narrowing in helper functions

function hasName(person: Person): person is Person & { name: string } {
  return person.name !== undefined;
}

if (hasName(person)) {
  const name1: string = person.name;
}

Mapping external data into safer internal types

A common pattern is to accept loose external data, then convert it into a stricter internal shape.

interface Person {
  name?: string;
}

interface CompletePerson {
  name: string;
}

function toCompletePerson(person: Person): CompletePerson {
  return {
    name: person.name ?? "Anonymous"
  };
}

Common Mistakes

Mistake 1: assuming optional means "usually there"

Optional means the property may be missing entirely.

interface Person {
  name?: string;
}

const person: Person = {};
console.log(person.name.toUpperCase()); // Runtime error

Fix

Check first or provide a default.

console.log((person.name ?? "Anonymous").toUpperCase());

Mistake 2: using type assertion to silence the error blindly

const name1: string = person.name as string;

This removes the error, but it does not make the value safe at runtime.

Fix

Use assertions only when you genuinely know the value exists.

Mistake 3: using || when ?? is more correct

const name1 = person.name || "Anonymous";

This treats empty strings like missing values.

For example, if person.name is "", the fallback will be used.

Better

const name1 = person.name ?? "Anonymous";

?? only falls back for null or undefined.

Mistake 4: making properties optional when they are actually required

interface Person {
  name?: string;
}

If your app logic requires every person to have a name, this type is too weak.

Fix

interface Person {
  name: string;
}

Mistake 5: forgetting strict null checks behavior

In TypeScript projects with strictNullChecks, missing values must be handled explicitly. Do not assume TypeScript will ignore undefined.

Comparisons

ApproachExampleSafe?When to use
Type checkif (person.name !== undefined) { ... }YesWhen you only want to proceed if the value exists
Default valueperson.name ?? "Anonymous"YesWhen you want a guaranteed fallback
Widen variable type`const name: stringundefined = person.name`Yes
Non-null assertionperson.name!SometimesOnly when you are certain the value exists
Type assertionperson.name as stringRiskyAvoid unless you fully control the data
Required propertyname: stringYesWhen the property should never be missing

?? vs ||

OperatorFalls back when value isGood for optional properties?
??null or undefinedYes
``
Take Quiz

Cheat Sheet

Optional property

interface Person {
  name?: string;
}

Reading name gives:

string | undefined

Why the error happens

const name1: string = person.name;
  • person.name might be undefined
  • string cannot contain undefined

Common fixes

1. Check first

if (person.name !== undefined) {
  const name1: string = person.name;
}

2. Use a fallback

const name1: string = person.name ?? "Anonymous";

3. Allow undefined

const name1: string | undefined = person.name;

4. Assert non-null only if certain

const name1: string = person.name!;

Prefer ?? over || for optional values

const name1 = person.name ?? "Anonymous";

If the property must exist, make it required

interface Person {
  name: string;
}

FAQ

Why does name?: string become string | undefined?

Because the property is optional, it may be missing. Reading a missing property gives undefined.

How do I assign an optional property to a string safely?

Use a check, a fallback value, or change the target variable type to string | undefined.

Should I use ! to fix this error?

Only if you are certain the value exists at runtime. It silences TypeScript but does not add safety.

What is the best default solution in most cases?

Using ?? is often the cleanest:

const name = person.name ?? "Anonymous";

What is the difference between ?? and || here?

?? only falls back for null or undefined. || also falls back for values like "", 0, and false.

Can I just change the interface instead?

Yes. If a property should always exist, make it required instead of optional.

Is this related to strictNullChecks?

Yes. This behavior is enforced when strict null checking is enabled, which is recommended in most TypeScript projects.

Take Quiz

Mini Project

Description

Build a small TypeScript utility that formats a user profile for display. The input object contains optional fields such as name, email, and city. The project demonstrates how to safely read optional properties, apply fallback values, and avoid unsafe assignments.

Goal

Create a function that accepts a partially filled user object and returns a display-ready profile with guaranteed string values.

Requirements

Requirement 1 Requirement 2 Requirement 3

Take Quiz

Keep learning

Related questions

View more