A simple guide to TypeScript interfaces: declaration & use cases
Tags: typescript, tutorial, programming, productivity
Published: 2022-09-14 21:24:03

TypeScript is a **superset of JavaScript** that introduces new features and helpful improvements to the language, including a powerful static typing system. By adding types to your code, you can spot or avoid errors early and get rid of errors at compilation.

In TypeScript, an **interface** is an abstract type that tells the compiler which property names a given object can have. TypeScript creates implicit interfaces when you define an object with properties. It starts by looking at the object's property name and data type using TypeScript's type inference abilities.

Today, you will learn how to create and work with interfaces in TypeScript to help add improved functionality to your projects. We will introduce you to the concept in detail with use cases.

**This tutorial at a glance:**
* [How to declare Typescript interfaces](#how)
* [Working with interfaces: use cases](#working)
* [Extending an interface](#extend)
* [Next steps for your learning](#next)

<a name="how"></a>

## Declaring Interfaces

An interface describes the shape of an object in [TypeScript](https://www.educative.io/blog/typescript-tutorial?eid=5082902844932096). They can be used to provide information about object property names and the datatypes their values can hold to the TypeScript compiler. An interface adds the functionality of strong type checking for your functions, variables, or the class that is implementing the interface. 

> Interfaces make sure that everything is implemented as expected.

Interfaces can be explicitly described or they can be implicitly created by the compiler, as it reads through objects in code. We declare an interface using the `interface` keyword in a `.ts` file. The following example shows an example of the syntax:

```typescript
interface Dimension {
    width: string;
    height: string;
}
```

Here, we defined an interface with the properties width and height that are both strings. Now we can implement the interface:

```typescript
interface Dimension {
    width: string;
    height: string;
}

let _imagedim: Dimension = {
    width: "200px",
    height: "300px"
};
```

Let's see another example. Here, we declare an interface named `User` with the `interface` keyword. The properties and methods that make up the interface are added within the curly brackets as `key:value` pairs, just like we add members to a plain JavaScript object.

```typescript
interface User {
  id: number;
  firstName: string;
  lastName: string;
  getFullName(): string;
}
```

We can use our newly created interface in code by adding an annotation to relevant objects. For example, here’s how to create a new user object with the User interface:

```typescript
const user: User = {
  id: 12,
  firstName: "Josh",
  lastName: "",
  getFullName: () => `${firstName} ${lastName}`
};
```

With this, our compiler knows what properties the user object is expected to have. If a property is missing, or if its value isn’t of the same type specified in the interface, the compiler will throw an error.

### Class Implementing Interface

We can use an interface with a class using the keyword `implements`, for example:

```typescript
class NameofClass implements InterfaceName {
}
```

Let's look at that interface working with a class. Here, we have an interface with width and height properties that are both type string. There is also a method `getWidth()` with a return value string.

```typescript
interface Size {
    width : string,
    height: string,
    getWidth(): string; 
}

class Shapes implements Size {
    width: string;
    height: string;
    constructor (width:string, height:string) {
        this.width = width;
        this.height = height;
    }
    getWidth() {
        return this.width;
    }
}
```

<a name="working"></a>

## Working with Interfaces

Now that we know how to declare interfaces, let's see them in action for a few common use cases.

### Specifying Optional Properties

In the previous code sample, all properties in the interface are required. If we create a new object with that interface and we leave out a property, the TypeScript compiler will throw an error.

There are certain cases, however, where we would expect our objects to have properties that are **optional**. We can achieve this by placing a question mark (`?`) just before the property’s type annotation when declaring the interface:

```typescript
interface Post {
  title: string;
  content: string;
  tags?: string[];
}
```

In this particular scenario, we tell the compiler that it is possible to have Post objects **without tags**.

It is very useful to describe interfaces in this way, especially if you want to prevent the use of properties not included in the interface.

```typescript
const validPostObj: Post {
  title: 'Post title',
  content: 'Some content for our post',
};

const invalidPostObj: Post = {
  title: 'Invalid post',
  content: 'Hello',
  meta: 'post description', // this will throw an error
  /* Type '{ title: string; content: string; meta: string; }' is not assignable to type 'Post'.

    Object literal may only specify known properties, and 'meta' does not exist in type 'Post'.
  */
};
```

### Specifying Read-only properties

It is also possible to mark a property in an interface as **read-only**. We can do this by adding the `readonly` keyword before a property’s key:

```typescript
interface FulfilledOrder {
  itemsInOrder: number;
  totalCost: number;
  readonly dateCreated: Date;
}
```

A read-only property can only be modified when an object is first created. That means if you try to reassign its value, the compiler will throw an error.

```typescript
const order: FulfilledOrder = {
 itemsInOrder: 1,
 totalCost: 199.99,
 dateCreated: new Date(),
};

order.dateCreated = new Date(2021, 10, 29);
```

> This behavior is similar to what happens when you try to reassign the value of a variable declared with the `const` keyword in JavaScript.

### Function and Class types

Interfaces can also be used to describe **function types**, and to check the structure of JavaScript [classes](https://www.educative.io/blog/object-oriented-programming#what-is?eid=5082902844932096).

To describe a function type with an interface, we give the interface a **call signature**. This is like a function declaration with only the parameter list and return type given.

```typescript
interface SumFunc {
  (a: number, b: number): number;
}

const add: SumFunc = (a, b) => {
  return a + b;
}
```

> **Note:** We did not need to specify the parameter type when creating our function.

The names of the parameters in your function and function type **do not need to match**. The compiler only checks the types of your function parameters, one at a time, in each corresponding parameter position.

We can also use interfaces to properly type classes created in JavaScript. To achieve this, we create an interface that contains the class’s properties and methods, then we use the implements keyword when creating our class.

```typescript
interface CarInterface {
  model: string;
  year: string;
  getUnitsSold(): number;
}

class Car implements CarInterface {
  model: string;
  year: string;
  getUnitsSold() {
    // logic to return number of units sold
    return 100;
  }

  constructor(model: string, year: string) {
    this.model = model;
    this.year = year;
  }
}
```

> **Note:** Our interfaces describe the public side of the class rather than both the public and private side.

### Generic Interfaces

Sometimes you might not know the type of data that each property in your interface would contain. The easy solution would be to just add any type to such properties. However, doing so would make our code **less type-safe**.

TypeScript lets you compose generic interfaces to help with scenarios like these. Generic interfaces are written like normal interfaces, but they allow you to set one or more parameters that can be included in the interface’s definition. 

> These parameters can be replaced with a type or another interface later in your code.

We can create a generic interface by passing type parameters, using angle brackets (`<>`), to our interface.

```typescript
interface PaginatedResponse<T> {
 data: T[];
 nextPageUrl?: string;
 previousPageUrl?: string;
}

interface Post {
 title: string;
 content: string;
 tags?: string[];
}

function loadDataFromApi() {
 fetch('/some/api/endpoint')
   .then((response) => response.json())
   .then((data: PaginatedResponse<Post>) => console.log(data));
}
```

The above example creates the `PaginatedResponse` interface that we can reuse to type the data returned from an API source. This can be reused across your code for different API resources with the same basic structure.

<a name="extend"></a>

## Extending an Interface

Just like classes, an interface can **extend another interface**. This allows you to copy members of one interface into another making them reusable. This gives you far more flexibility. 

An interface can extend a single interface, multiple interfaces, or a class, using the `extends` keyword. We can extend multiple interfaces when they are separated by commas. 

```typescript
interface PetsInterface {
  name: string;  
}
interface DogInterface extends PetsInterface {
  breed: string;
}
interface CatInterface extends PetsInterface {
  breed: string;
}
```

To implement both our `Dog` and `Cat` interfaces, we also implement the `Pets` interface. 

```typescript
interface PetsInterface {
  name: string;  
}
interface DogInterface extends PetsInterface {
  breed: string;
}
interface CatInterface extends PetsInterface {
  breed: string;
}
class Cat implements CatInterface {
  name: string = 'Garfield';
  breed: string = 'Tabby';
}
class Dog implements DogInterface {
  name: string = 'Rover';
  breed: string = 'Poodle';
}
```

## What to learn next

Congratulations on making it to the end! Interfaces are a powerful tool that make errors easier to detect at compile-time. TypeScript is a powerful tool that makes complex JavaScript projects easier. In fact, TypeScript brings many other features to help you write maintainable and reusable code. 

**Some of these features that you should learn next include:**
* Utility Types
* Union and Intersection Types
* Enums
* Type Guards
* Type Aliases

To learn these tools and advance your TypeScript skills, check out Educative’s curated learning path **[TypeScript for Front-End Developers](https://www.educative.io/path/typescript-for-front-end-developers?eid=5082902844932096)**. This path will allow you to painlessly transition your JavaScript experience to TypeScript. By the end, you'll know how to use advanced TypeScript in professional projects.

Whether you're new to TypeScript or looking to advance your skills, this is your one-stop-Typescript shop.

*Happy learning!*

## Continue reading about TypeScript on Educative

* [Understanding Advanced Concepts in Typescript](https://www.educative.io/blog/advanced-typescript-concepts?eid=5082902844932096)
* [Getting started with React and TypeScript](https://www.educative.io/blog/react-and-typescript?eid=5082902844932096)
* [TypeScript Tutorial: a step-by-step guide to learn Typescript](https://www.educative.io/blog/typescript-tutorial?eid=5082902844932096)

### Start a discussion
Why do you think TypeScript is a good language to pickup? Was this article helpful? Let us know in the comments below!