家事国事天下事事事有心 發表於 2025-12-28 10:59:47

TypeScript之字面量类型的使用详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">✳️ 一、什么是字面量类型(Literal Types)?</a></li><li><a href="#_label1">🧠 为什么要有字面量类型?</a></li><li><a href="#_label2">✳️ 二、字面量类型 VS 基础类型的区别</a></li><li><a href="#_label3">✳️ 三、什么时候会推断为字面量类型?</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_0">✅ 1.const声明的变量,会推断为字面量类型</a></li><li><a href="#_lab2_3_1">✅ 2. 使用as const明确指定字面量类型</a></li><li><a href="#_lab2_3_2">✅ 3. 明确写了字面量类型</a></li><li><a href="#_lab2_3_3">❌ 不会推断为字面量类型的情况</a></li></ul><li><a href="#_label4">✳️ 四、推断字面量类型的实际应用场景</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_4">1. 联合类型的类型保护</a></li><li><a href="#_lab2_4_5">2. 字面量值作为 discriminated union 的 tag</a></li><li><a href="#_lab2_4_6">3. 使用as const提供精确值类型</a></li></ul><li><a href="#_label5">✅ 总结:字面量类型核心知识表</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>✳️ 一、什么是字面量类型(Literal Types)?</h2>
<p>在 TypeScript 中,<strong>字面量类型</strong>(Literal Types)是<strong>值级别的类型</strong>,表示某个值本身就是类型的一部分。</p>
<p>常见的字面量类型包括:</p>
<table><thead><tr><th>字面量类型</th><th>举例</th></tr></thead><tbody><tr><td>数字</td><td>1, 42, 0</td></tr><tr><td>字符串</td><td>&quot;hello&quot;, &quot;yes&quot;</td></tr><tr><td>布尔</td><td>true, false</td></tr></tbody></table>
<p>这些类型只接受对应的字面值:</p>
<div class="jb51code"><pre class="brush:js;">type A = 1;
const x: A = 1;       // ✅ 合法
const y: A = 2;       // ❌ 报错:不能赋值 number 给类型 1
</pre></div>
<p class="maodian"><a name="_label1"></a></p><h2>🧠 为什么要有字面量类型?</h2>
<p>字面量类型让我们可以更严格、更精确地控制值的合法性。</p>
<p>比如在按钮组件中:</p>
<div class="jb51code"><pre class="brush:js;">type ButtonSize = 'small' | 'medium' | 'large';

function createButton(size: ButtonSize) { ... }

createButton('medium'); // ✅
createButton('huge');   // ❌ 类型错误
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>✳️ 二、字面量类型 VS 基础类型的区别</h2>
<table><thead><tr><th>字面量类型</th><th>宽泛基础类型</th></tr></thead><tbody><tr><td>&#39;hello&#39;</td><td>string</td></tr><tr><td>1</td><td>number</td></tr><tr><td>true</td><td>boolean</td></tr></tbody></table>
<p>你可以认为字面量类型是基础类型的&ldquo;子类型&rdquo;。</p>
<div class="jb51code"><pre class="brush:js;">let a: 'yes' = 'yes';       // ✅
let b: string = 'yes';      // ✅
a = b;                      // ❌ string 可能不等于 'yes'
b = a;                      // ✅ 'yes' 一定是 string
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>✳️ 三、什么时候会推断为字面量类型?</h2>
<p>这是关键!我们来看 TypeScript 中<strong>推断为字面量类型的几种情况</strong>:</p>
<p class="maodian"><a name="_lab2_3_0"></a></p><h3>✅ 1.const声明的变量,会推断为字面量类型</h3>
<div class="jb51code"><pre class="brush:js;">const a = 42;       // 推断为 42(字面量类型)
let b = 42;         // 推断为 number(更宽泛)
</pre></div>
<div class="jb51code"><pre class="brush:js;">const s = "hello";// 推断为 "hello"
let t = "hello";    // 推断为 string
</pre></div>
<p>🧠 <strong>原理:</strong> <code>const</code> 声明表示变量值不可变,所以可以精确地推断为值本身的类型。</p>
<p class="maodian"><a name="_lab2_3_1"></a></p><h3>✅ 2. 使用as const明确指定字面量类型</h3>
<div class="jb51code"><pre class="brush:js;">const arr = as const;
// 推断为 readonly (字面量元组)
</pre></div>
<div class="jb51code"><pre class="brush:js;">const obj = {
type: 'success',
code: 200,
} as const;
// 推断为 { readonly type: 'success'; readonly code: 200 }
</pre></div>
<p>📌 <code>as const</code> 是字面量推断的强制方式,常用于需要精准类型的地方,比如 Redux、API 返回值、类型映射。</p>
<p class="maodian"><a name="_lab2_3_2"></a></p><h3>✅ 3. 明确写了字面量类型</h3>
<p>当然,最直接的方法就是你直接指定类型:</p>
<div class="jb51code"><pre class="brush:js;">let status: 'loading' | 'done' = 'loading';
</pre></div>
<p class="maodian"><a name="_lab2_3_3"></a></p><h3>❌ 不会推断为字面量类型的情况</h3>
<table><thead><tr><th>情况</th><th>推断类型</th><th>原因</th></tr></thead><tbody><tr><td>let a = 42;</td><td>number</td><td>因为 let 变量是可变的</td></tr><tr><td>const a = someFunc();</td><td>非字面量</td><td>如果返回值无法静态分析成字面量</td></tr><tr><td>const obj = { key: &#39;value&#39; };</td><td>{ key: string }</td><td>对象属性默认是宽泛类型,除非加 as const</td></tr></tbody></table>
<p class="maodian"><a name="_label4"></a></p><h2>✳️ 四、推断字面量类型的实际应用场景</h2>
<p class="maodian"><a name="_lab2_4_4"></a></p><h3>1. 联合类型的类型保护</h3>
<div class="jb51code"><pre class="brush:js;">type Action = 'increment' | 'decrement';

function reducer(action: Action) {
if (action === 'increment') {
    // ✅ Narrowing to 'increment'
}
}
</pre></div>
<p class="maodian"><a name="_lab2_4_5"></a></p><h3>2. 字面量值作为 discriminated union 的 tag</h3>
<div class="jb51code"><pre class="brush:js;">type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };

function getArea(shape: Shape) {
if (shape.kind === 'circle') {
    return Math.PI * shape.radius ** 2;
}
}
</pre></div>
<p class="maodian"><a name="_lab2_4_6"></a></p><h3>3. 使用as const提供精确值类型</h3>
<div class="jb51code"><pre class="brush:js;">const options = ['up', 'down'] as const;
type Direction = typeof options; // 'up' | 'down'
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>✅ 总结:字面量类型核心知识表</h2>
<table><thead><tr><th>知识点</th><th>说明</th></tr></thead><tbody><tr><td>字面量类型定义</td><td>1, &quot;hi&quot;, true 等</td></tr><tr><td>推断为字面量的条件</td><td>const 声明、as const、手动指定字面量类型</td></tr><tr><td>推断不会是字面量的情况</td><td>let、函数返回值、普通对象/数组字面量</td></tr><tr><td>实际用途</td><td>更精确的类型检查、discriminated union、配置常量、枚举替代等</td></tr></tbody></table>
頁: [1]
查看完整版本: TypeScript之字面量类型的使用详解