Skip to content

TypeScript Interfaces

Interfaces are one of TypeScript's core principles, used to define the "shape" or "contract" of an object. Interfaces only describe what properties and methods an object should contain, without concerning themselves with the specific implementation. This is very useful for team collaboration and code standards.

What is an Interface?

An interface is a way to define the structure of an object. You can use it to specify what properties an object must have and the types of those properties.

Basic Example

typescript
// Define an interface
interface LabeledValue {
    label: string;
}

function printLabel(labeledObj: LabeledValue) {
    console.log(labeledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };

// myObj has a label property of type string, so it conforms to the LabeledValue interface
printLabel(myObj); // OK

TypeScript's type checker only cares whether an object has the properties and types required by the interface, not whether the object has other properties. This is called "duck typing."

Interface Features

1. Optional Properties

Not all properties in an interface are required. You can mark a property as optional by adding ? after the property name.

typescript
interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    let newSquare = { color: "white", area: 100 };
    if (config.color) {
        newSquare.color = config.color;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare1 = createSquare({ color: "black" });
let mySquare2 = createSquare({ width: 20 });

2. Readonly Properties

Some properties can only be modified when the object is first created. You can specify readonly properties by using readonly before the property name.

typescript
interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
// p1.x = 5; // Error: Cannot assign to 'x' because it is a read-only property.

3. Function Types

Interfaces can also describe function types. To do this, the interface needs to contain a call signature, which is like a function definition with only a parameter list and return value type.

typescript
interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(src, sub) {
    let result = src.search(sub);
    return result > -1;
}

4. Indexable Types

Interfaces can describe types that can be "indexed," like arrays and objects.

typescript
// Describe a string array
interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];

// Describe a dictionary object
interface NumberDictionary {
    [index: string]: number;
    length: number; // Can include other properties
}

Classes Implementing Interfaces

A common use of interfaces is to force a class to satisfy a specific contract. Classes can use the implements keyword to implement one or more interfaces.

typescript
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date): void;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

Interface Inheritance

Like classes, interfaces can inherit from each other. This allows you to copy members from one interface to another, creating more flexible and reusable components.

typescript
interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

// Square interface inherits from Shape and PenStroke
interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = {} as Square;
square.color = "blue";
square.penWidth = 5.0;
square.sideLength = 10;

Interfaces vs. Type Aliases

Interfaces and type aliases (type) can sometimes be used interchangeably, but there are some key differences:

  • Extensibility: Interfaces can be extended (extends) and can be merged with same-name declarations (declaration merging). Type aliases cannot be extended or merged, but can simulate extension through intersection types (&).
  • Usage: If you're defining the "shape" of an object, or want it to be implementable by classes (implements), using an interface is the better choice. If you need to define union types, tuples, or other non-object types, you should use type aliases.

Overall, interfaces are a powerful tool for defining code contracts and standards.

Content is for learning and research only.