DEV Community

Cover image for undefined in Optional Types: The Gotcha No One Warned Me About
Werliton Silva
Werliton Silva

Posted on • Edited on

undefined in Optional Types: The Gotcha No One Warned Me About

🤯 “Wait… Why Is undefined Allowed Here?”

Meet Tchaaca - a junior developer working on a TypeScript codebase for the first time. While refactoring some legacy JavaScript into TypeScript, he proudly writes:

function greet(name?: string) {
  console.log(`Hello, ${name ?? "guest"}!`);
}
Enter fullscreen mode Exit fullscreen mode

So far, so good.

But a few lines later, his senior dev does this:

greet(undefined); // no error
Enter fullscreen mode Exit fullscreen mode

Tchaaca frowns.

“Hold on... I thought name? meant optional. Why can we pass undefined explicitly? Shouldn’t TypeScript stop that?”

That’s when confusion kicks in - and it happens to most of us.


đź’ˇ What ? Really Means in TypeScript

When you write:

function greet(name?: string)
Enter fullscreen mode Exit fullscreen mode

It’s shorthand for:

function greet(name: string | undefined)
Enter fullscreen mode Exit fullscreen mode

So yes, undefined is allowed - both implicitly and explicitly.

? means: “This can be missing - or be undefined.”

That’s why both of these work:

greet();           // âś… OK - omitted
greet(undefined);  // âś… OK - explicit undefined
Enter fullscreen mode Exit fullscreen mode

đź§  So... What's the Problem?

For many teams, especially those transitioning from JS to TS, allowing explicit undefined can lead to:

  • Confusion between omitting vs manually passing undefined
  • Bugs when passing undefined to required functions or props
  • Inconsistent coding practices

đźš« Preventing Manual undefined with ESLint

If you want to avoid explicitly passing or assigning undefined, you can enforce that with ESLint.

📦 Install the necessary packages:

npm install eslint @typescript-eslint/parser 
@typescript-eslint/eslint-plugin --save-dev
Enter fullscreen mode Exit fullscreen mode

đź”§ .eslintrc.js setup:

module.exports = {
  parser: "@typescript-eslint/parser",
  plugins: ["@typescript-eslint"],
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  rules: {
    "no-undefined": "error" // ⛔️ Prevent manual usage of undefined
  }
};
Enter fullscreen mode Exit fullscreen mode

❌ Will throw ESLint error:

let name: string | undefined;
name = undefined; // đź”´ ESLint: 'undefined' is not allowed
Enter fullscreen mode Exit fullscreen mode

âś… Still allows optional omission:

function greet(name?: string) {
  // Using undefined for checks is still fine
  if (name === undefined) {
    console.log("Guest");
  }
}
Enter fullscreen mode Exit fullscreen mode

🛡️ Bonus: Use strictNullChecks in tsconfig.json

To avoid nullish bugs entirely, turn on:

{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true
  }
}
Enter fullscreen mode Exit fullscreen mode

This ensures TypeScript treats undefined and null strictly and never assumes they’re just “nothing.”


đź§µ Final Thoughts

Tchaaca learned that name?: string is more powerful - and subtle - than it looks. It doesn’t reject undefined, it accepts it. Which is great when you're okay with that... but confusing when you're not.

If you want to avoid accidentally introducing undefined manually, the fix isn’t in TypeScript - it’s in your lint rules.

So next time you're puzzled by what ? means, remember:

"Optional" means "maybe undefined" - and yes, even on purpose.

Top comments (1)

Collapse
 
werliton profile image
Werliton Silva

Tips and more tips forU guys