TypeScript Interface Method and Method Parameters

Updated: January 7, 2024 By: Guest Contributor Post a comment

Introduction

TypeScript enhances JavaScript by adding type definitions, one powerful feature is the ability to define methods and their parameters within an interface to enforce structure on classes and objects. In this tutorial, we’ll explore how to use methods and parameters within TypeScript interfaces.

Defining Interface Methods

Interfaces in TypeScript allow us to define a contract within our code. We start by creating an interface with a method signature.

interface UserGreeter {
  greet(name: string): string;
}

Any object or class that implements this interface is required to provide an implementation of the greet method exactly as it’s described.

class User implements UserGreeter {
  greet(name: string) {
    return `Hello, ${name}!`;
  }
}

const user = new User();
console.log(user.greet('Alice')); // 'Hello, Alice!'

Working with Method Parameters

Method parameters within interfaces can be given types, default values, and marked as optional. Let’s explore these features.

Typed Method Parameters

interface Calculator {
  add(x: number, y: number): number;
}

// Implementing class
class SimpleCalculator implements Calculator {
  add(x: number, y: number): number {
    return x + y;
  }
}

Optional Parameters

interface LoggerInterface {
  log(message: string, userId?: string): void;
}

class Logger implements LoggerInterface {
  log(message: string, userId?: string) {
    if (userId) {
      console.log(`${userId}: ${message}`);
    } else {
      console.log(`Guest: ${message}`);
    }
  }
}

Default Parameters

interface Greeting {
  sayHello(name: string, greeting: string = 'Hello'): void;
}

// Note: Interface itself can't contain the default parameter value; it's in the implementing class

class EnglishGreeter implements Greeting {
  sayHello(name: string, greeting: string = 'Hello'): void {
    console.log(`${greeting}, ${name}!`);
  }
}

Advanced Method Signatures

TypeScript interfaces are not limited to simple methods; they can also describe more complex behaviors.

Function Overloading in Interfaces

interface SearchFunc {
  (source: string, subString: string): boolean;
  (source: string, subStrings: string[]): boolean;
}

// Function implementing the overloaded interface
function search(source: string, subString: string | string[]): boolean {
  if (typeof subString === 'string') {
    return source.includes(subString);
  } else {
    return subString.some(sub => source.includes(sub));
  }
}

Indexable Types

interface StringArray {
  [index: number]: string;
  length: number;
}

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

Implementing Interfaces with Classes and Functions

Beyond simple type checking, interfaces also blend seamlessly with classes and functions.

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

class Clock implements ClockInterface {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
}

function createClock(ctor: { new(): ClockInterface }): ClockInterface {
  return new ctor();
}

let digitalClock = createClock(Clock);

Extending Interfaces

Interfaces can extend one another, allowing for the composition of complex types and functionality.

interface Shape {
  draw(): void;
}

interface PenStroke {
  penWidth: number;
}

interface Circle extends Shape, PenStroke {
  radius: number;
}

let circle: Circle;

Generics with Interfaces

Generics provide the ability to use an interface with various types while still retaining type safety.

interface ResultContainer<T> {
  result: T;
  add: (a: T, b: T) => T;
}

class NumberResultContainer implements ResultContainer<number> {
  result: number;
  add(a: number, b: number): number {
    return a + b;
  }
}

Conclusion

Understanding and utilizing TypeScript interface methods and method parameters is fundamental for leveraging TypeScript’s full power. These capabilities enable us to design clear, type-safe APIs and contracts within our codebases. It’s a cornerstone of TypeScript’s structural type system and an indispensable tool for writing robust applications.