◆ decimal でも有効桁数以下は丸められるだけ
  ◆ C# や Python を見ると 28 桁ほどあるけどそんなに必要なことはほぼない
◆ 0.1 が正確に表現できず誤差はあるけどほんの僅か
  ◆ 影響出るほどの計算を繰り返すことは現実的に考えづらい
  ◆ 心配なら計算の度に toPrecision や toFixed で文字列化してから再度数値化すればいい
◆ 注意するのは小数に対して一致確認や比較するとき
  ◆ 文字列比較や再数値化しないと誤差の影響で求めてる結果にならないかも
  ◆ 簡単に対処できるものなのでわざわざライブラリを入れたりサーバ側で処理するほどじゃない

JavaScript って数値型は int/float 型の違いがなく number のみで double 型相当なので小数点以下で誤差が出るから金額みたいな正確性が必要な計算に向いてないという話を見かけました
decimal 型はないので そうではあるのですけど 大抵の計算には十分な有効桁数があるので ほとんどの場合は気にするほどでもないと思います

有効桁数

組み込みで decimal 型のある C# と Python を見てみると C# は 28 ~ 29 桁の有効桁数があり Python は変更可能ですがデフォルトでは 28 桁の有効桁数です
こんな桁の計算をすることはめったにないでしょう

それに decimal は固定小数点で小数点以下◯桁は必ず計算されるか というとそういうものではないです

C# で 1÷7 を計算すると循環小数なのでずっと続いて有効桁数の 28 桁までが表示されます
それに整数の 1234567890 を足すと整数部に 10 桁使われるので小数部の末尾の方は失われます

var num = 1m / 7m;

Console.WriteLine("{0}", num);
// 0.1428571428571428571428571429

num = num + 1234567890m;

Console.WriteLine("{0}", num);
// 1234567890.1428571428571428571

末尾は丸められます

有効桁数を小さくできてわかりやすい Python で試してみます

import decimal

ctx = decimal.getcontext()
ctx.prec = 3

print(ctx.create_decimal(2.13) / 2)
# 1.06

print(ctx.create_decimal(2.15) / 2)
# 1.08

ctx.prec = 10

print(ctx.create_decimal(2.13) / 2)
# 1.065000000

print(ctx.create_decimal(2.15) / 2)
# 1.075000000

デフォルトの丸め挙動は ROUND_HALF_EVEN なので偶数丸めです
四捨五入だと 1 つ目が 1.07 になるはずですが 1.06 です

JavaScript で同じ計算をしてみます

> 2.13/2
1.065

当たり前ですが 有効桁数 3 桁の結果より正確に計算されてますよね
0.001 の桁を四捨五入して 0.01 の桁までにしたいのなら 1.065 を四捨五入して 1.07 にできます
JavaScript ではとても小さいところで誤差が出ていると言っても有効桁数的に問題なければ正確な結果を得られます

1÷7 の計算結果は有効桁数の小さい decimal よりも JavaScript のほうがより下の桁まで計算結果を保持しているので正確です

>>> import decimal
>>> ctx = decimal.getcontext()
>>> ctx.prec = 8
>>> ctx.create_decimal("1") / 7
Decimal('0.14285714')

> 1/7
0.14285714285714285

デフォルトの decimal 型は有効桁数がとても大きいですが その大きさがいらないなら JavaScript で困りません
JavaScript の number 型は 15 ~ 16 桁の有効桁数です
1 億なら 9 桁でまだ小数部に 6 桁ほど残っているので 0.1 や 0.01 の桁までしか扱わないなら十分正確な値です

0.1

他の decimal 型の利点に正確に値を表現できるというものがあります
0.5 は JavaScript でも正確に表現できますが 0.1 はできません

> 0.5.toFixed(30)
'0.500000000000000000000000000000'
> 0.1.toFixed(30)
'0.100000000000000005551115123126'

有効桁数外には誤差が存在します
僅かな誤差ですが繰り返し計算すると誤差が大きくなってきます

> let n = 0
undefined
> for (let i=0;i<1000000;i++) n += 0.1
100000.00000133288

更に繰り返し回数を増やして 1000 億回 0.1 を足すと

> let n = 0
undefined
> for (let i=0;i<100_000_000_000;i++) n += 0.1
10000018871.664534

上位 7 桁目に誤差が入ってきました
ですがこれだけの回数 小数値を繰り返し計算することは通常ないと思います
掛け算で 0.1 × 1000 億 とするとこうはならないですし

現実的な回数の計算なら影響出るほどの誤差にはならないはずです
どうしても心配なら計算するたびに toPrecision で精度指定の文字列化をしてから再度数値化することで誤差の蓄積をなくせます
10 桁もあれば十分なのでとりあえず 10 桁にしてます

> let n = 0
undefined
> for (let i=0;i<1000000;i++) {
... n += 0.1
... n = +(n.toPrecision(10))
... }
100000

0.3333...

逆に decimal のほうが不便なところで割り切れない場合の値がもとに戻らないというのがあります

1÷3 をしてその結果に 3 を掛けます

>>> import decimal
>>> ctx = decimal.getcontext()
>>> d = ctx.create_decimal("1") / 3
>>> d
Decimal('0.3333333333333333333333333333')
>>> d * 3
Decimal('0.9999999999999999999999999999')

Python も C# も同様です
有効桁数まで 3 が続いていて それが正確な値として扱われるので 3 を掛けると 9 が並びます

JavaScript だと

> const d = 1/3
undefined
> d
0.3333333333333333
> d * 3
1

と 1 になります
これは JavaScript 以外の言語でも float や double 型を使えば同じ結果になるはずです

気をつけるところ

そういう感じなので別に JavaScript でも困ってません

ただ たまーにやってしまいがちなのは 小数計算後にそのまま === でリテラルと比較です
有名なものですが 0.1 と 0.2 を足したものが 0.3 と一致しません

> 0.1 + 0.2 === 0.3
false

前述の通り誤差が存在して その誤差の部分が微妙に違うため異なる値になります

> (0.1 + 0.2).toFixed(20)
'0.30000000000000004441'
> 0.3.toFixed(20)
'0.29999999999999998890'

toFixed で小数点以下◯桁までの文字列にして文字列比較をしたり toFixed や toPrecision で文字列化したものを数値化してから比較したりが必要です

> (0.1 + 0.2).toFixed(1) === "0.3"
true
> +(0.1 + 0.2).toPrecision(10) === 0.3
true

この辺が面倒といえば面倒ですが その程度でライブラリを入れたりサーバ側で計算させたりするほうが何倍も面倒だと思います

一応 Proposal には Stage1 ですが Decimal の提案があります
全然進んでないのでいつになるのか不明ですが BigInt みたいに組み込み型として使えるようになればもう少し楽になるかもしれませんね