Annuities are cool. They're fixed payments over a period of time. If you're living in England, there's another financial product called a consol that is an annuity that pays out in perpetuity. Amazing.

Below are simplified examples of how to calculate present value and future value for annuities. I wasn't intending to create a calculator as much as provide a really simple way to think about all the magic Microsoft Excel does behind the scenes.

Theres a lot of room for improvement but I think this is a pretty good starting point.

// Description
// https://helloacm.com/common-javascript-functions-for-financial-calculations/

class Currency{
    static toUSD(num) {
        num = Math.round(num * 100) * 0.01;
        var currstring = num.toString();
        if (currstring.match(/\./)) {
            var curr = currstring.split('.');
        } else {
            var curr = [currstring, "00"];
        }
        curr[1] += "00";
        curr[2] = "";
        var returnval = "";
        var length = curr[0].length;
        
        // add 0 to decimal if necessary
        for (var i = 0; i < 2; i++) 
            curr[2] += curr[1].substr(i, 1);
     
        // insert commas for readability
        for (i = length; (i - 3) > 0; i = i - 3) {
            returnval = "," + curr[0].substr(i - 3, 3) + returnval;
        }
        returnval = curr[0].substr(0, i) + returnval + "." + curr[2];
        return(returnval);
    }
}
class Finance {
    constructor(){
    }
    // Present Value Interest Factor for Annuities
    // AKA: The present value of $1 a year for T years at an interest rate of R
    PVIFA(rate, periods){
        let annuityFactor = (1 - 1 / Math.pow(1 + rate, periods)) / rate;
        // Truncate the value by 4 decimals
        return annuityFactor.toFixed(4)
    }
    // Future Value of an Annuity
    FVIFA(rate, periods){
        let annuityFactor = (Math.pow(1 + rate, periods) - 1) / rate;
        return annuityFactor
    }
    // Present Value of an Annuity
    Annuity(cashflow, rate, periods){
        return cashflow * this.PVIFA(rate, periods)
    }
    // Discounts are also known as opportunity costs
    Discount(cashflow, rate, periods){
        var discount = cashflow / Math.pow(1 + rate, periods)
        return discount;        
    }
    // Present Value of Perpetuity
    Perpetuity(cashflow, rate){
        let presentValue = cashflow / rate;
        return presentValue;
    }
    // Present Value for Growing Perpetuity
    GrowingPerpetuity(cashflow, discountRate, growthRate){
        let presentValue = cashflow / (discountRate - growthRate);
        return presentValue;
    }
    calculateAnnuity(){
        // STEP 1 - Calculate the Present Value from the start of the Annuity
        var cashflow = 50000;
        var periods = 20;
        var rate = 0.08;
        var pv = this.Annuity(cashflow, rate, periods);

        console.log("Present Value of Annuity #1: ", Currency.toUSD(pv));
    }
    calculateDelayedAnnuity(){
        // Payment amount per period.
        var amount = 500;
        // Interest Rate
        var rate = 0.10;
        // The number of periods the investor has to wait to then start seeing payouts.
        var periods = 5;
        // The number of periods required for the annuity to mature
        var maturityDate = periods - 1;
        var pv = this.Annuity(amount, rate, maturityDate);

        // Discount the present value of the annuity back to Date 0
        var discount = this.Discount(pv, rate, periods);

        console.log("Present Value of Annuity #2: ", Currency.toUSD(pv))
        console.log("Present Value of Delayed Annuity #2: ", Currency.toUSD(discount));
    }
    calcualteFutureValueOfAnnuity(){
        var cashflow = 3000;
        var periods = 30;
        var rate = 0.06
        var fv = cashflow * this.FVIFA(rate, periods);

        console.log("Future Value of an Annuity: ", Currency.toUSD(fv));
    }
    calculateAnnuityDue(){
        var cashflow = 50000;
        var rate = 0.08;
        // Since the annuity will make its first payment today, you must subtract it.
        var periods = 20;
            periods = periods - 1;
        // After you've calculated the 19 year annuity you must add back the initial payment
        var pv = cashflow + this.Annuity(cashflow, rate, periods);
        console.log("Annuity Due: ", Currency.toUSD(pv));
    }
    calculatePerpetuity(){
        var cashflow = 10000;
        var rate = 2.5;
        var consol = this.Perpetuity(cashflow, rate)
        console.log( "Perpetuity: ", Currency.toUSD(consol) );
    }
    calcualteGrowingPerpetuity(){
        var cashflow = 100000;
        var discountRate = 0.11;
        var growthRate = 0.05;
        var presentValue = this.GrowingPerpetuity(cashflow, discountRate, growthRate);
        console.log( "Growing Perpetuity: ", Currency.toUSD(presentValue) )
    }
}

const finance = new Finance();
    finance.calculateAnnuity();
    finance.calculateDelayedAnnuity()
    finance.calculateAnnuityDue();
    finance.calcualteFutureValueOfAnnuity();
    finance.calculatePerpetuity();
    finance.calcualteGrowingPerpetuity();