A Money Extension Type That Makes 0.1 + 0.2 == 0.3 Fail Loudly, Not Silently
Dart's extension types turn a money precision bug from a runtime surprise into a compile error, at zero runtime cost. Here's the pattern.
0.1 + 0.2 == 0.3 evaluates to false in Dart, for the same reason it does in almost every language: binary floating point can't represent most decimal fractions exactly (0.1 + 0.2 actually comes out to 0.30000000000000004). It's a well-known trap, and "just don't use double for money" is well-known advice. The gap is usually enforcement — nothing stops a teammate, six months from now, from doing exactly that in a hurry.
The pattern: wrap it so the compiler enforces it #
Dart 3's extension types are zero-cost wrappers: no runtime object, no boxing, just a compile-time view over an underlying representation that restricts what you can do with it.
extension type Money._(int minorUnits) {
factory Money.fromMinorUnits(int minorUnits) = Money._;
Money operator +(Money other) => Money._(minorUnits + other.minorUnits);
Money operator -(Money other) => Money._(minorUnits - other.minorUnits);
bool operator >(Money other) => minorUnits > other.minorUnits;
double get asMajorUnits => minorUnits / 100;
@override
String toString() => (minorUnits / 100).toStringAsFixed(2);
}Store everything in integer minor units (cents, paise — whatever your smallest denomination is) under the hood. The extension type means Money only supports the operations you defined on it.
What this actually buys you #
final balance = Money.fromMinorUnits(1000); // ₹10.00
final fee = 0.2; // someone reached for a raw double
balance + fee; // compile error: no operator matching (Money, double)That's the entire point. A precision bug that would previously surface as a support ticket — "my balance is off by a fraction of a cent" — instead fails the build, in the IDE, before it's ever committed. Money has no + overload that accepts a double, so there's no code path where one silently gets summed against minor units.
Worth noting
This isn't a runtime validation library — there's no exception to catch, because there's nothing to catch. The type system rules the mixed arithmetic out before the code compiles, which is a stronger guarantee than any test suite can give you.
Where it still needs a human decision #
Extension types stop you from accidentally mixing money and raw numbers. They don't decide your rounding rule, your display currency, or what happens to a fractional minor unit after a percentage split — those are still product and finance decisions that belong in code review, not in the type system. The type system's job here is narrow and specific: make the easy mistake impossible, and leave the hard decisions visible.
Stuck on this in your own app?
This is the kind of problem I help fintech teams get right the first time — see how App Architecture & Consulting engagements work, or just tell me what you're building.