Categories
TypeScript

Using TypeScript — Objects

Spread the love

TypeScript is a natural extension of JavaScript that’s used in many projects in place of JavaScript.

However, not everyone knows how it actually works.

In this article, we’ll look at how to work with objects in TypeScript.

Shape Types

We can define shape types that restrict the types of an object.

For instance, we can write:

const obj: { foo: number; bar?: sting } = { foo: 1 };

We have an object type with the property foo that is a number and the property bar that is optional and has the data type string.

The ? after the name indicates that it’s optional.

The structure must match what’s set for the object to be assigned to the variable.

We can also include methods in object shape types.

For instance, we can write:

const obj: { name: string; greet(greeting: string): string } = {
  name: "james",
  greet(greeting) {
    return `${greeting} ${this.name}`;
  }
};

Now we have a greet method in the object shape type, which is required.

It takes a greet parameter with the data type string and also returns a string.

Like value properties, methods can also be optional.

For instance, we can write:

const obj: { name: string; greet?(greeting: string): string } = {
  name: "james"
};

Then we can omit the greet method in the object we assign to obj if we wish.

Strict Checking for Methods

We can set the strictNullChecks option to true in tsconfig.json to prevent undefined values from being set in shape types.

With it on, we can write something like:

const obj: { name: string; greet?(greeting: string): string } = {
  name: undefined
};

We’ll get the error ‘Type ‘undefined’ is not assignable to type ‘string’.ts(2322)‘.

Type Aliases for Shape Types

Since writing shape types are such a pain, we can assign it to a type alias so that we can use the alias instead of specifying the same type everywhere.

For instance, we can write:

type person = { name: string; greet?(greeting: string): string };

Now we can rewrite our assignment statement as follows:

const obj: person = {
  name: "jame"
};

Excess Properties

The TypeScript compiler is good at inferring types, which means that data types can be skipped sometimes.

For instance, if we have:

type person = { name: string };
const obj = {
  name: "jame",
  age: 10
};

const james: person = obj;

It’s smart enough to match the shape of obj and the person type and finger that obj is of type person .

Shape Type Unions

Shape types can form a union type with other shape types.

For instance, we can write:

type Person = { name: string };
type Location = { city: string };
const obj = {
  name: "jame",
  city: "new york"
};

const james: Person | Location = obj;

Person | Location is a data type that has both the properties of name and city .

Union Property Types

Properties can also have union types as their data type.

For instance, we can write:

type Person = { id: number | string; name: string };
const obj = {
  name: "jame",
  id: 1
};

Now id can be a number or a string.

Type Guards for Objects

We can add type guards for objects just like we do with other types.

For instance, we can write:

type Person = { name: string };
type Animal = { breed: string; name: string };

const person = {
  name: "jame"
};

const animal = {
  name: "jame",
  breed: "dog"
};

const arr: (Person | Animal)[] = [person, animal];
arr.forEach(a => {
  console.log(typeof a);
});

We loop through the person and animal objects which are put into the arr array.

Then we loop through them with forEach to find out the type.

Inside the callback, we use the typeof keyword to look at the type and see that they’re both type object just like they are in JavaScript.

Checking Properties

This means that we can’t use the typeof operator to check the type of objects.

Instead, we must find better alternatives.

One way is to check if a property is in the object.

For instance, we can use the in operator:

arr.forEach(a => {
  if ("breed" in a) {
    console.log("animal");
  } else {
    console.log("person");
  }
});

The in operator checks if the 'breed' property is in an object.

It checks both its own and inherited properties.

And it returns true if a property is found in any of those places and false otherwise.

However, this doesn’t help us if a property is in both types.

Conclusion

We can define object shape types.

This way, we can check the structure of the object and the property types.

We can assign them to a data type alias to make our lives easier by avoiding repetition.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *