Blog post

Common TypeScript Issues Nº 5: Optional property declarations

Blog Author Phil Nash

Phil Nash

Developer Advocate JS/TS

7 min read

  • SonarQube for IDE
  • TypeScript
  • JavaScript
  • ESLint
Common mistake in Typescript #5

We crunched the data from SonarQube for IDE to discover the top 5 most common TypeScript issues. In this 5 part series, we outline each issue and how to avoid it.


We encourage you to install SonarQube for IDE in your editor and follow along with the examples below. Make sure you have a valid tsconfig.json in your working directory or run npx tsc --init to create one.

In at Nº 5: Optional property declarations

Optional object properties are properties that can hold a value or be undefined. In TypeScript there are a few ways to declare an optional object property.


You can use a union, like this:

// index.ts
interface Person {
  name: string;
  address: string | undefined;
}

const john: Person = {
  name: "John",
};

This might look fine, but if you check it out in your editor you’ll see that the TypeScript compiler doesn’t agree. To fulfill the type definition you need to provide the address property on the object even if it is undefined.

// index.ts
interface Person {
  name: string;
  address: string | undefined;
}

const john: Person = {
  name: "John",
  address: undefined,
};

Alternatively, you can use the optional property syntax like this:

// index.ts
interface Person {
  name: string;
  address?: string;
}

const john: Person = {
  name: "John",
};

Now TypeScript is happy with this, which means that using the optional property syntax must be behaving differently to the union type we started with.


With the first example, we are requiring that the property is always defined, even when the value itself is undefined. This is important in cases when you enumerate the properties of an object. That is, whether the address property is set to undefined or to a string, accessing Object.keys(john).length will always return 2.


With the second example using ? we are saying that it is OK if the property is not defined at all. Technically both examples mean accessing the address property on the object john will evaluate to undefined, but in the second example Object.keys(john).length is now 1. Each version communicates to other developers in your project the way you expect this interface to be used, either the address property should be explicitly set, or it doesn’t matter if it is set or not.


Which brings us to number 5 in our list of common TypeScript issues: optional property declarations should not use both `?` and `undefined` syntax.


Try the following code in your editor with SonarQube for IDE:

// index.ts
interface Person {
  name: string;
  address?: string | undefined;
}

const john: Person = {
  name: "John",
};

Perhaps this happens when you first write the union type of string | undefined and then you find that TypeScript complains that you aren’t explicitly setting the property everywhere. So you add the optional property syntax to it and the compilation errors go away.


However, now your type gives no indication of how it should be used. The optional syntax means that you don’t need to provide the property explicitly, but the union type suggests that you should. As discussed above, using either option communicates your intention to other developers in the project, but using both communicates nothing and is ultimately confusing. This lint rule ensures that you pick one or the other and avoid confusion:

Animated GIF showing how SonarLint picks up and corrects a TypeScript issue optional property declaration.

If you want to avoid getting caught by this TypeScript issue you can default to using the optional property syntax and use the union type with caution. If you have SonarQube for IDE installed in your editor then you won’t make this mistake because you will be alerted as it happens.

What’s coming next?

Optional property declarations place fifth in our list of the top 5 most common TypeScript issues. Next week we'll reveal fourth place on the list.


Is this a mistake you’ve made before and did you think it would be so common? What do you think will make up the rest of the top 5? Let us know on Twitter at @SonarSource or in the community.


Free Video! Best practices to improve your JavaScript coding.
Watch now
  • Legal documentation
  • Trust center
  • Follow SonarSource on Twitter
  • Follow SonarSource on Linkedin

© 2008-2024 SonarSource SA. All rights reserved. SONAR, SONARSOURCE, SONARQUBE, and CLEAN AS YOU CODE are trademarks of SonarSource SA.