AI Dev Lab
HeirShare

HeirShare ができるまで — 相続税の早見表ロジックを実装する

相続税シミュレーターの開発ログ。 家族構成から法定相続人と相続分を判定し、 基礎控除・課税遺産総額・速算表・配偶者の税額軽減まで、 早見表と同じ順序を素の JavaScript で実装した過程を記録しています。

相続税は、多くの人にとって「一生に数回、突然向き合うことになる」税金です。しかも計算がややこしい。

「うちは相続税かかるの?」「かかるとしたらいくら?」——この最初のざっくりした見当をつけたいだけなのに、調べ始めると基礎控除、法定相続分、速算表、配偶者の税額軽減……と専門用語が次々出てきて、多くの人はそこで手が止まります。税理士に相談する前の、その手前の「概算」が欲しい。

HeirShare は、遺産の総額と家族構成を入れるだけで相続税の目安を出すツールです。国税庁の早見表と一致する計算を、全部ブラウザの中でやります。


#🎯 「概算でいい」に振り切る

最初に決めたのは、厳密さより見通しを優先することでした。

実際の相続税申告は、不動産の評価、小規模宅地等の特例、生前贈与の加算など、個別事情で大きく変わります。それを全部入れると入力項目が数十個になり、「ざっくり知りたい」人には重すぎる。

なので HeirShare は、課税価格の合計家族構成という最小の入力から、標準的なケースの税額を出すことに絞りました。特例や個別評価が絡む場合は税理士へ、という線引きを明確にしています。この割り切りがないと、そもそも使ってもらえるツールになりません。


#🏗️ 相続税計算の 4 ステップ

相続税は、順を追えば機械的に計算できます。HeirShare の中身もその順番どおりです。

  1. 法定相続人を確定する(誰が何割か)
  2. 基礎控除を引く(ここまでは非課税)
  3. 法定相続分で按分して、各人の税額を速算表で出し、合算する
  4. 配偶者の税額軽減を適用する

順に見ていきます。

#ステップ1: 法定相続人と法定相続分

相続人には順位があります。配偶者は常に相続人で、それ以外は「子 → 直系尊属(父母)→ 兄弟姉妹」の順で、上位がいれば下位は相続人になりません。

ts
if (children > 0) {
 // 第1順位: 子
 spouseShare = spouse ? 0.5 : 0
 const childrenTotal = spouse ? 0.5 : 1
 if (spouse) heirs.push({ role: "配偶者", share: 0.5, count: 1 })
 heirs.push({ role: "子", share: childrenTotal / children, count: children })
} else if (parents > 0) {
 // 第2順位: 直系尊属
 spouseShare = spouse ? 2 / 3 : 0
 ...
} else if (siblings > 0) {
 // 第3順位: 兄弟姉妹
 spouseShare = spouse ? 0.75 : 0
 ...
}

配偶者と子なら配偶者 1/2・子 1/2、配偶者と父母なら 2/3・1/3、配偶者と兄弟姉妹なら 3/4・1/4。この分数は民法で決まっていて、同順位が複数いれば頭割りします。childrenTotal / children が、子全体の取り分を人数で割っている部分です。

#ステップ2: 基礎控除

相続税には「ここまでは非課税」という基礎控除があります。

ts
const basicDeduction = 30_000_000 + 6_000_000 * count
const taxableEstate = Math.max(0, input.taxable - basicDeduction)

3,000 万円 + 600 万円 × 法定相続人の数。たとえば配偶者と子 2 人なら人数は 3 なので、3,000 + 1,800 = 4,800 万円まで非課税です。遺産がこの額以下なら相続税はかかりません。「うちはかかるの?」の答えは、まずここで大半が決まります。

#ステップ3: 速算表で税額を出す

ここが相続税独特のところで、いったん「法定相続分どおりに分けた」と仮定して各人の税額を計算し、合算するという手順を踏みます。実際の分け方に関わらず、まず総額を確定させるためです。

ts
function sokusan(amount: number): number {
 const table: Array<[number, number, number]> = [
 [10_000_000, 0.1, 0],
 [30_000_000, 0.15, 500_000],
 [50_000_000, 0.2, 2_000_000],
 [100_000_000, 0.3, 7_000_000],
 [200_000_000, 0.4, 17_000_000],
 [300_000_000, 0.45, 27_000_000],
 [600_000_000, 0.5, 42_000_000],
 [Infinity, 0.55, 72_000_000],
 ]
 if (amount <= 0) return 0
 for (const [cap, rate, deduct] of table) {
 if (amount <= cap) return Math.max(0, amount * rate - deduct)
 }
 return 0
}

これは国税庁が公開している「相続税の速算表」そのものです。税額 = 取得金額 × 税率 − 控除額 という形で、累進課税を 1 行で計算できるようになっています。各段の控除額は、税率が上がる境目で税額が連続するよう逆算された値です。

各法定相続人の分を速算表にかけて足し合わせたものが、相続税の総額になります。

ts
totalTax = Math.floor(totalTax / 100) * 100 // 100 円未満切り捨て

#ステップ4: 配偶者の税額軽減

最後が、相続税で最も効く優遇である配偶者の税額軽減です。

ts
if (input.spouse && input.taxable > 0) {
 const cap = Math.max(input.taxable * spouseShare, 160_000_000)
 const spouseActual = input.taxable * input.spouseRatio
 const spouseTax = totalTax * input.spouseRatio
 if (spouseActual <= cap) spouseRelief = spouseTax
 else spouseRelief = totalTax * (cap / input.taxable)
}

配偶者は、法定相続分か 1.6 億円の多いほうまで相続しても相続税がかかりません。Math.max(法定相続分, 1.6億円) が、その非課税の上限です。多くの家庭では、配偶者がこの範囲で相続する限り配偶者分の税額はゼロになります。

この軽減があるため、「配偶者がいるかどうか」で最終的な納税額は大きく変わります。HeirShare が家族構成を最初に聞くのは、ここに効いてくるからです。


#😓 苦労したところ

#すべて「円」の整数で持つ

税額計算は端数処理が細かく決まっています。相続税の総額は 100 円未満切り捨て、といったルールを正しく反映するには、途中で浮動小数の誤差を出したくない。

そこで内部の金額は全部円単位の整数で保持し、表示のときだけ「万円」に変換しています。「1.6 億円」も 160_000_000 と円で持つ。桁は大きくなりますが、JavaScript の数値は相続税の額くらいなら整数精度を保てるので、誤差の心配がありません。

#早見表と突き合わせる

自分の計算が正しいかは、国税庁や各種サイトが公開している「相続税の早見表」(遺産額×家族構成の一覧)と照合しました。「配偶者と子 2 人で 1 億円ならいくら」といった代表的なケースを何通りも当てて、早見表と一致することを確認しています。税金の計算は、自分の実装を信じるより、公開されている答えと突き合わせるのが確実です。

#「概算です」を隠さない

相続税は、実際には不動産の評価方法や特例で数百万円単位で変わります。ツールの数字を「確定額」と思われると、かえって害になる。

なので HeirShare は、標準的なケースの概算であること、個別事情で変わること、正式には税理士・税務署へ、という但し書きを画面に明記しています。お金と税金を扱うツールでは、できないことを正直に書くのが信頼の条件だと考えています。


#🔭 今後の拡張

  • 2 割加算 — 配偶者・子・親以外(兄弟姉妹や孫など)が相続する場合の加算
  • 未成年者控除・障害者控除 — 該当する相続人がいる場合の控除
  • 生前贈与の加算 — 相続開始前一定期間の贈与を足し戻す
  • 実際の分け方での各人の納税額 — 総額だけでなく「誰がいくら払うか」まで

ただし増やすほど入力が重くなるので、「概算ツール」の軽さを壊さない範囲で選ぶことになります。


#💡 このサービスから言えること

制度をそのままコードにできる領域がある。 相続税は、法定相続分も基礎控除も速算表も、すべて公開された数式とルールで決まっています。曖昧さのない制度は、順番どおりに実装すれば早見表と一致する。占いのような解釈の余地がない分、「合っているか」を客観的に検証できるのが、この手のツールを作るときの強みです。

もうひとつは、入力を絞る勇気です。相続税を完全に正確に計算しようとすると入力欄が数十個になり、誰も使いません。「概算でいい」に振り切って最小入力に絞ったことで、初めて役に立つツールになりました。何を入れるかより、何を入れないかを決めるほうが、実は難しくて大事な設計判断でした。

[ ./next_action ]

読んだら、 HeirShare を実際に動かす。

この開発ログは HeirShare をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
ToonCast

ToonCast ができるまで — AnimeGANv2 をブラウザで動かす

AnimeGANv2 の小さな ONNX (約9MB) を onnxruntime-web (単一スレッド WASM=COOP/COEP不要、 color-revive で承認済みライブラリの再利用) で実行。 512x512・[-1,1] 正規化で推論し、 結果を元解像度に戻して表示する設計記録。 写真は端末内処理。

read log →
ColorRevive

ColorRevive ができるまで — onnxruntime-web で白黒写真をカラー化

DeOldify の量子化 ONNX を onnxruntime-web (CDN side-load・単一スレッド WASM=COOP/COEP不要) で実行。 256x256 でモデル推論し、 輝度は元写真・色だけ AI を YCbCr で再合成して輪郭を保つ設計記録。 写真は端末内処理。

read log →
PhotoTwin

PhotoTwin ができるまで — CLIP画像埋め込みで似た写真を見つける

CLIP (Xenova/clip-vit-base-patch32) の image-feature-extraction を transformers.js の CDN ESM で side-load し、 各写真を正規化ベクトル化。 cosine 類似度で重複・似た写真をブラウザ内で検出する設計記録 (新ライブラリ追加なし=what-cam と同じ CLIP の再利用)。

read log →
AkinFind

AkinFind ができるまで — ブラウザ内で完結する embeddings 意味検索

多言語の文章埋め込みモデル (Xenova/multilingual-e5-small) を transformers.js の CDN ESM で side-load し、 各文を正規化ベクトル化。 cosine 類似度で意味検索と似ている文ペア検出を全て端末内で行う設計記録。

read log →
WhatCam

WhatCam ができるまで — CLIP のゼロショット画像分類をブラウザで動かす

CLIP (Xenova/clip-vit-base-patch32) を transformers.js の CDN ESM で side-load し、 写真と候補ラベルの近さをブラウザ内で計算。 日本語ラベルを英語プロンプトに変換し、 図鑑と自由入力の両モードで「これ何?」を判定する設計記録。

read log →
DepthCast

DepthCast ができるまで — 1枚の写真をAIの深度推定で立体にする

Depth Anything (transformers.js) を CDN ESM で side-load し、 1枚の写真から深度マップを推定。 WebGL2 フラグメントシェーダで深度に比例した視差 (iterative backward parallax) を作り、 赤青アナグリフ / WebM 書き出しまで端末内で完結させた設計記録。

read log →