Optional Properties and Defaults

When a value might not be there

8 min read

Not everything is always filled in

Real data is messy. A user might not have added a nickname yet. A product might not have a discount. TypeScript handles this with optional properties: add a question mark after the property name in an interface, and that property becomes allowed-but-not-required:

interface User {
  name: string;
  email: string;
  nickname?: string;
}

const withNick: User = { name: 'Gwen', email: 'g@x.com', nickname: 'Gwe' };
const without: User = { name: 'Sam', email: 's@x.com' };

Both objects are valid users. The question mark on nickname? tells TypeScript, and every human reading the code, that this field may simply not be there.

TypeScript makes you check first

Here is the clever part. Because nickname might be missing, its type is really string | undefined, and TypeScript will not let you use it carelessly:

function shout(user: User): string {
  return user.nickname.toUpperCase();
}

That gets an error: 'user.nickname' is possibly 'undefined'. The fix is to check before using it, exactly the way careful JavaScript developers already do:

function shout(user: User): string {
  if (user.nickname) {
    return user.nickname.toUpperCase();
  }
  return user.name.toUpperCase();
}

Inside the if block, TypeScript understands the value is definitely a string, so the call is safe. This one feature prevents an entire family of bugs, the infamous cannot read properties of undefined crash that every JavaScript developer has met.

Default parameter values

Functions have a related tool: give a parameter a default, and callers can leave it out entirely. TypeScript even infers the type from the default value:

function makeGreeting(name: string, punctuation = '!'): string {
  return 'Hello, ' + name + punctuation;
}

makeGreeting('Gwen');
makeGreeting('Gwen', '?');

Because the default is '!', TypeScript knows punctuation is a string without an annotation. Calling with a number, like makeGreeting('Gwen', 3), is an error.

Optional vs default: use a question mark for data that may genuinely be absent, like a nickname. Use a default value when there is a sensible fallback the function should use automatically, like ending a greeting with '!'.

Quick check

Q1 In an interface, what does the question mark in nickname?: string mean?

Q2 Why does TypeScript complain when you call user.nickname.toUpperCase() on an optional property without checking it first?

Want to save your progress? It's free.

Create a free account