Open In App

Invariant in TypeScript

Last Updated : 06 Jun, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

An invariant is a situation that does not change or alter all the time the program runs. It works as an assurance or limitation on the state of an object, data structure, or system. Invariants make sure that specific properties are maintained all the time which also prevents any abrupt behaviors and errors from occurring.

Example: To demonstrate creating a banking system coded in TypeScript which will enforce a rule with regard to the account's balance, one that does not permit an account's balance to be less than zero.

JavaScript
class BankAccount {
    private balance: number;

    constructor(initialBalance: number) 
    {
        // Enforce the invariant 
        // during initialization
        if (initialBalance < 0)
         {
            throw new Error("Initial balance cannot be negative");
        }
        this.balance = initialBalance;
    }

    deposit(amount: number): void {
        // Enforce the invariant before 
        // modifying the balance
        if (amount < 0) {
            throw new Error("Deposit amount must be positive");
        }
        this.balance += amount;
    }

    withdraw(amount: number): void 
    {
        // Enforce the invariant before 
        // modifying the balance
        if (amount < 0) {
            throw new Error("Withdrawal amount must be positive");
        }
        if (this.balance - amount < 0)
         {
            throw new Error("Insufficient funds");
        }
        this.balance -= amount;
    }

    getBalance(): number {
        return this.balance;
    }
}

// Example usage
const account = new BankAccount(1000);
// Creating an account with initial balance of 1000

console.log("Initial balance:", account
.getBalance());
// Output: Initial balance: 1000

account.deposit(500);
// Depositing 500
console.log("Balance after deposit:", account
.getBalance());
// Output: Balance after deposit: 1500

account.withdraw(200); // Withdrawing 200
console.log("Balance after withdrawal:", account
.getBalance());
// Output: Balance after withdrawal: 1300

// Trying to withdraw more than
//  the balance (should throw an error)
try {
    account.withdraw(1500);
} catch (error)
{
    console.error(error.message);
    // Output: Insufficient funds
}

Output:

Initial balance: 1000
Balance after deposit: 1500
Balance after withdrawal: 1300
Insufficient funds

Explanation:

In this example, we have a BankAccount class that has methods for depositing, withdrawing and getting the balance. We ensure that before modifying any changes to the balance variable it should never be negative, if an exception occurs (e.g. withdrawal exceeding balance), then the account balance will remain correct.

Importance of Invariants

In software development, invariants are very important for the following reasons-

  • Maintaining Consistency: One can make sure that the state of an application has not been changed by ensuring that invariants are followed thus lowering the possibility for bugs occurring or unexpected behavior happening.
  • Enhancing Code Readability: Clear and precise statements about how parts of a system should behave made available by using invariants which will help to make code more readable and understandable.
  • Facilitating Debugging: Invariants act as check points during development and debugging processes hence it will make easier to identify areas which might have gone wrong.

Best Practices

Use the best practices below for a more effective use of invariants in TypeScript-

  • Document Invariants: This will help you understand and maintain your code if you properly document the different parts of your codebase which dictate what happens to them.
  • Test Invariants: Compose unit tests in order to confirm that invariants remain valid when tested versus multiple scenarios* and edge situations.
  • Enforce Invariants Early: If invariants fail then it becomes necessary to optimize the system during development process rather than later.
  • Refactor as Needed: Over time, regularly check on and reorganize the code base so that you can know if there are still relevant invariants correctly followed according to application changes.

Conclusion

As, guards of the software’s stability and correctness, invariants remain intrinsic to software development. With TypeScript, developers can use type system and language features to achieve effective enforcement of invariants thereby creating more resilient and dependable applications.


Next Article

Similar Reads