add js-fp3

This commit is contained in:
Oli Sturm
2026-04-24 18:04:54 +01:00
parent e61b4d4c11
commit b1ac745d70
8 changed files with 446 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
import { ok, fail } from '../library/result.js';
/**
* @typedef {Object} Account
* @property {string} id
* @property {import('./money.js').Money} balance
*/
/** @typedef {{ type: 'OpeningBalanceMustBeNonNegative' }} OpeningBalanceMustBeNonNegative */
/** @typedef {{ type: 'AmountMustBePositive' }} AmountMustBePositive */
/** @typedef {{ type: 'InsufficientBalance', balance: import('./money.js').Money, amount: import('./money.js').Money }} InsufficientBalance */
/** @typedef {{ type: 'AccountNotFound', accountId: string }} AccountNotFound */
/** @typedef {OpeningBalanceMustBeNonNegative | AmountMustBePositive | InsufficientBalance | AccountNotFound} AccountError */
/**
* @type {OpeningBalanceMustBeNonNegative}
*/
export const openingBalanceMustBeNonNegative = { type: 'OpeningBalanceMustBeNonNegative' };
/**
* @type {AmountMustBePositive}
*/
export const amountMustBePositive = { type: 'AmountMustBePositive' };
/**
* @param {import('./money.js').Money} balance
* @param {import('./money.js').Money} amount
* @returns {InsufficientBalance}
*/
export const insufficientBalance = (balance, amount) => ({
type: 'InsufficientBalance',
balance,
amount,
});
/**
* @param {string} accountId
* @returns {AccountNotFound}
*/
export const accountNotFound = (accountId) => ({
type: 'AccountNotFound',
accountId,
});
/**
* @param {string} id
* @param {import('./money.js').Money} openingBalance
* @returns {import('../library/result.js').Result<Account, AccountError>}
*/
export const openAccount = (id, openingBalance) =>
openingBalance.amount < 0
? fail(openingBalanceMustBeNonNegative)
: ok({ id, balance: openingBalance });
/**
* @param {Account} account
* @param {import('./money.js').Money} amount
* @returns {import('../library/result.js').Result<Account, AccountError>}
*/
export const withdraw = (account, amount) => {
if (amount.amount <= 0) {
return fail(amountMustBePositive);
}
if (account.balance.amount < amount.amount) {
return fail(insufficientBalance(account.balance, amount));
}
return ok({
...account,
balance: { amount: account.balance.amount - amount.amount },
});
};
+16
View File
@@ -0,0 +1,16 @@
/**
* @typedef {Object} Money
* @property {number} amount
*/
/**
* @param {number} amount
* @returns {Money}
*/
export const createMoney = (amount) => ({ amount });
/**
* @param {Money} money
* @returns {string}
*/
export const formatMoney = (money) => money.amount.toFixed(2);