Functions in TypeScript

Learn how to use Functions in TypeScript with this detailed tutorial. Includes basic and advanced examples to help you master Functions.

Introduction

Functions are the fundamental building blocks in JavaScript and TypeScript. They allow you to encapsulate logic, create reusable code, and define APIs. TypeScript enhances functions by allowing you to define types for parameters and return values.

Basic Examples

Here are some basic examples of using Functions in TypeScript:

Function Declarations

You can define a function in TypeScript with typed parameters and a typed return value.

function add(x: number, y: number): number {
    return x + y;
}

console.log(add(2, 3)); // 5

Function Expressions

Functions can also be defined using function expressions.

let myAdd = function(x: number, y: number): number {
    return x + y;
};

console.log(myAdd(2, 3)); // 5

Optional and Default Parameters

Parameters can be made optional by using the ? symbol, and default values can be provided.

function buildName(firstName: string, lastName?: string): string {
    if (lastName) return firstName + " " + lastName;
    else return firstName;
}

console.log(buildName("Bob")); // Bob
console.log(buildName("Bob", "Smith")); // Bob Smith

function buildNameWithDefault(firstName: string, lastName: string = "Smith"): string {
    return firstName + " " + lastName;
}

console.log(buildNameWithDefault("Bob")); // Bob Smith
console.log(buildNameWithDefault("Bob", "Johnson")); // Bob Johnson

Rest Parameters

You can use rest parameters to accept multiple arguments.

function buildName(firstName: string, ...restOfName: string[]): string {
    return firstName + " " + restOfName.join(" ");
}

console.log(buildName("Joseph", "Samuel", "Lucas", "MacKinzie")); // Joseph Samuel Lucas MacKinzie

Overloads

Function overloads allow you to define multiple signatures for a function.

function pickCard(x: { suit: string; card: number; }[]): number;
function pickCard(x: number): { suit: string; card: number; };
function pickCard(x: any): any {
    if (typeof x == "object") {
        return Math.floor(Math.random() * x.length);
    } else if (typeof x == "number") {
        let suits = ["hearts", "spades", "clubs", "diamonds"];
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [
    { suit: "diamonds", card: 2 },
    { suit: "spades", card: 10 },
    { suit: "hearts", card: 4 }
];
let pickedCard1 = myDeck[pickCard(myDeck)];
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);

Advanced Examples

Here are some advanced examples of using Functions in TypeScript:

This Parameters

You can explicitly indicate that a method does not use the class instance using this.

class Deck {
    suits = ["hearts", "spades", "clubs", "diamonds"];
    cards = Array(52);
    createCardPicker(this: Deck) {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
            return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
        };
    }
}

let deck = new Deck();
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();

console.log("card: " + pickedCard.card + " of " + pickedCard.suit);

Function Types

You can define function types and use them as types for variables.

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

let mySearch: SearchFunc;

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

console.log(mySearch("Hello, world", "world")); // true
console.log(mySearch("Hello, world", "foo")); // false

Generic Functions

You can use generics to create functions that work with different types.

function identity(arg: T): T {
    return arg;
}

let output1 = identity("myString"); // output1 is of type string
let output2 = identity(42); // output2 is of type number

Constraints on Generics

You can impose constraints on generic types to limit the types they accept.

interface Lengthwise {
    length: number;
}

function loggingIdentity(arg: T): T {
    console.log(arg.length);
    return arg;
}

loggingIdentity({ length: 10, value: 3 });

Using Class Types in Generics

You can use class types in generics to create more flexible and reusable components.

function create(c: { new(): T }): T {
    return new c();
}

class BeeKeeper {
    hasMask: boolean = true;
}

class ZooKeeper {
    nametag: string = "Mikle";
}

class Animal {
    numLegs: number = 4;
}

class Bee extends Animal {
    keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
    keeper: ZooKeeper = new ZooKeeper();
}

function createInstance(c: new () => A): A {
    return new c();
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!

Function Overloads

Function overloads allow you to provide multiple function signatures for a single function.

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === "number") {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === "string") {
        return x.split('').reverse().join('');
    }
}

console.log(reverse(12345)); // 54321
console.log(reverse("hello")); // olleh

Arrow Functions

Arrow functions provide a shorter syntax for writing functions and do not have their own this context.

let sum = (x: number, y: number): number => {
    return x + y;
};

console.log(sum(2, 3)); // 5

Conclusion

Functions in TypeScript provide a powerful way to encapsulate logic, create reusable code, and define APIs. By using typed parameters and return values, you can catch errors early and improve the readability and maintainability of your code. Whether you are working on a small project or a large-scale application, mastering functions in TypeScript will help you write more reliable and efficient code.