TypeScript の as const で型が絞り込めない
実環境で検証済み
`as const` はリテラル型と readonly 化を行うが、配置場所を間違えると効かない。
配列やタプル全体に付ける必要があり、関数の戻り値で union 化を保ちたいなら戻り値式に付ける。
要素単位の as const では狙った narrowing が起きない。
公開: 更新:
要約
as const は値式に対して 3 つの効果を持つ: リテラル型の widening を止める、配列をタプルにする、プロパティを readonly にする。
これらは「式単位」で効くため、配置場所を 1 つズラすだけで意図と違う型になる。
union narrowing を狙うときは「外側全体」に付け、関数の戻り値でリテラルを保ちたいなら return 式に付ける。
よくある原因
- 要素単位で付けている:
[1 as const, 2 as const]は[1, 2]ではなく(1 | 2)[]のままで、タプル化が起きない。
配列全体に付けないとタプルにならない。 - 戻り値で widening:
function foo() { return [42, 'ok']; }は(string | number)[]に widened される。
タプル[number, string]にしたいならreturn [42, 'ok'] as const。 - 型注釈での上書き:
const x: string[] = ['a', 'b'] as constは注釈側が優先され、リテラル情報が消える。
注釈を外すかas constのみにする。 - satisfies の不在: 型チェックは欲しいが widening は避けたいケースで
satisfiesを使わないと、注釈の型に合わせて広がる。
解決策
1. 配列全体に as const
const routes = ["home", "about", "contact"] as const;
// type Routes = "home" | "about" | "contact"
type Routes = (typeof routes)[number];const assertions の導入記事(新しいタブで開く) に挙動の網羅例がある。
2. 戻り値式に as const
function parse(input: string) {
if (input === "") return ["err", "empty"] as const;
return ["ok", input] as const;
}
const r = parse("hi");
if (r[0] === "ok") {
// r[1]: string
}タプル化と union 判別が同時に効き、r[0] での判別だけで r[1] の型も絞られる。
3. satisfies で型チェックと両立
const colors = {
primary: "#0070f3",
danger: "#ef4444",
} as const satisfies Record<string, `#${string}`>;satisfies を後ろに置くと、型チェックは効くが推論型はリテラルのまま残る。as const だけ → as const satisfies T が定石。
4. discriminated union の作成
type Event =
| { kind: "click"; x: number; y: number }
| { kind: "key"; code: string };
const evt = { kind: "click", x: 1, y: 2 } as const satisfies Event;kind 側もリテラル化されるため、関数で Event を受けたときに kind === "click" で narrowing が効く。
実行例
実際に上記の手順を node:20 環境で動かすと、TypeScript 5.9.3 のもとで as const なしのコード(bad.ts)は TS2322(終了コード 2)を返し、戻り値式に as const を追加したコードでは終了コード 0 となり、エラーが解消されることを確認できる。
== versions ==
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
v20.20.2
Python 3.11.2
git version 2.39.5
This is not the tsc command you are looking for
To get access to the TypeScript compiler, tsc, from the command line either:
- Use npm install typescript to first add TypeScript to your project before using npx
- Use yarn to avoid accidentally running code from un-installed packages
v10.7.0
== run ==
--- TypeScript を install ---
Version 5.9.3
--- NG: as const 無し。戻り値が string[] に widening し r[0] が string のまま(TS2322 を想定)---
src/bad.ts(6,7): error TS2322: Type 'string' is not assignable to type '"ok" | "err"'.
tsc の終了コード: 2
--- 解決: 戻り値式に as const を付けてタプル+リテラル union にする ---
tsc の終了コード: 0(0 = 解消)— 2026-07-11 時点の出力