impl/typescript.ts
1,932 bytes · the TypeScript implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { age } from "./dates_age.ts"; ← from dates.age ^1.0.0 · built alongside by fune
import { type AgeBand, type AgeBanding } from "./insurance_age_banding_types.ts";
/**
* The policyholder's age on the inception date and the band it falls in.
*
* Age is completed years by dates.age, so a 29 February birthday ages on
* 1 March in other years. The bands are checked before use: youngest first,
* inclusive at both ends, no overlaps, and only the last may be open-ended.
* An age no band covers is an error, not the nearest band.
*/
export function ageBand(birthDate: string, inceptionDate: string, bands: readonly AgeBand[]): AgeBanding {
if (bands.length === 0) throw new RangeError("bands must not be empty");
let previousMax = -1;
for (let i = 0; i < bands.length; i++) {
const band = bands[i];
if (!Number.isInteger(band.minAge) || band.minAge < 0) {
throw new RangeError(`minAge must be a whole number of 0 or more, received ${band.minAge}`);
}
const open = band.maxAge === null || band.maxAge === undefined;
if (open && i !== bands.length - 1) {
throw new RangeError(`only the last band may have no maxAge: "${band.label}" is not last`);
}
if (!open && (!Number.isInteger(band.maxAge) || (band.maxAge as number) < band.minAge)) {
throw new RangeError(`maxAge must be a whole number no less than minAge in band "${band.label}"`);
}
if (band.minAge <= previousMax) {
throw new RangeError(`bands must be youngest first and not overlap: "${band.label}" starts at ${band.minAge}`);
}
previousMax = open ? Number.MAX_SAFE_INTEGER : (band.maxAge as number);
}
const years = age(birthDate, inceptionDate);
for (const band of bands) {
const open = band.maxAge === null || band.maxAge === undefined;
if (years >= band.minAge && (open || years <= (band.maxAge as number))) {
return { age: years, label: band.label };
}
}
throw new RangeError(`no band for age ${years}`);
}