TypeScript: Object with Optional Properties

Updated: December 15, 2023 By: Frienzied Flame Post a comment

In TypeScript, a powerful and popular static type-checker for JavaScript, we often encounter scenarios where an object’s properties may not always be mandatory. In such cases, we leverage optional properties to keep our code flexible and robust. This comprehensive tutorial with code examples will guide you through the concept of optional properties in TypeScript.

Understanding Optional Properties

In TypeScript, optional properties are those properties that are not obligatory in an object’s structure. To denote a property as optional, we use a question mark ? right after the property’s name. This gives us the ability to create flexible object structures where certain properties may or may not be present.

type User = {
  name: string;
  age?: number;
}

In the code snippet above, age is an optional property in the User object.

Creating Optional Properties

There are several ways to create optional properties in TypeScript. They can be defined in type aliases, interfaces, and classes.

Type Aliases

type Person = {
  name: string;
  age?: number;
}

Classes

class Person {
  name: string;
  age?: number;

  constructor(name: string, age?: number) {
    this.name = name;
    this.age = age;
  }
}

In each of these examples, the property age is optional.

Interfaces

Optional properties in interfaces are defined using the same syntax as in type aliases and classes. Here’s an example:

interface Person {
  email: string;
  name?: string;
  phone?: string;
}

In this interface, name and phone are optional properties.

Dealing with Undefined

When accessing an optional property that has not been assigned a value, TypeScript returns undefined. This is expected behavior as the property is not required to have a value.

interface Person {
  name: string;
  age?: number;
}

let person: Person = {
  name: "John Doe"
}

console.log(person.age) // undefined

However, TypeScript also allows us to explicitly assign an undefined value to an optional property.

interface Person {
  name: string;
  age?: number;
}

let person: Person = {
  name: "John Doe",
  age: undefined
}

console.log(person.age) // undefined

Configuring ExactOptionalPropertyTypes

By using the exactOptionalPropertyTypes option in the tsconfig.json file, we can prevent TypeScript from assigning undefined to an optional property. This option is part of the compilerOptions section.

{
  "compilerOptions": {
    "exactOptionalPropertyTypes": true,
    "strictNullChecks" : true
  }
}

When this option is enabled, trying to assign undefined to an optional property will result in a compiler error.

Utilizing Partial Utility Type

TypeScript provides utility types that allow us to construct new types from existing ones. The Partial utility type is one such resource. It converts all properties of a given type to optional.

interface Person {
  name: string;
  address: string;
  age: number;
}

let person: Partial<Person> = {}

In this example, the Partial utility type is used to make all properties of the Person interface optional.

Function with Optional Properties

Optional properties can also be used in functions. In the following example, the printInfo function accepts a Person object as a parameter, and it prints the information of the person.

interface Person {
  email: string;
  name?: string;
  phone?: string;
}

function printInfo(person: Person) {
  console.log('Email:', person.email);
  if (person.name) {
    console.log('Name:', person.name);
  }
  if (person.phone) {
    console.log('Phone number:', person.phone);
  }
}

In TypeScript, both optional parameters and parameters of type number | undefined allow for the argument to be omitted. However, a function with an optional parameter allows the function to be called without any arguments, whereas a function expecting a parameter of type number | undefined requires at least one argument.

Conclusion

Mastering optional properties in TypeScript can significantly improve your coding skills and open up new ways to handle data structures. As we’ve seen, optional properties offer flexibility and robustness when defining object structures, allowing for properties to be absent when they’re not needed. By using optional properties, we can write cleaner, more maintainable code that can handle a variety of data scenarios.