型(Type from Value)完全指南:從 `const` 字面量到類(lèi)型收窄)
文檔教程【免費(fèi)下載鏈接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.項(xiàng)目地址https://gitcode.com/gh_mirrors/typ/typescript-book點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本文以《The Concise TypeScript Book》西班牙語(yǔ)版的 type-from-value.md 章節(jié)為核心系統(tǒng)講解 TypeScript 的從值推斷類(lèi)型機(jī)制編譯器如何根據(jù)一個(gè)值或表達(dá)式自動(dòng)推導(dǎo)出類(lèi)型const與let在推斷上的差異、字面量類(lèi)型的放大widening與收窄、as const斷言與泛型const修飾符等進(jìn)階手段。讀完本文你將掌握 TypeScript 類(lèi)型推斷的核心規(guī)則能夠準(zhǔn)確預(yù)判const x x這類(lèi)表達(dá)式最終得到的類(lèi)型并能在實(shí)際項(xiàng)目中利用推斷寫(xiě)出既簡(jiǎn)潔又類(lèi)型安全的代碼。一、什么是從值推斷類(lèi)型Type from Value從值推斷類(lèi)型是 TypeScript 中最基礎(chǔ)也最重要的能力之一編譯器自動(dòng)從一個(gè)值或表達(dá)式中推斷出它的類(lèi)型而不需要開(kāi)發(fā)者顯式書(shū)寫(xiě)類(lèi)型注解。原文檔給出了它的定義與最經(jīng)典的示例const x x; // TypeScript infers x as a string literal with const (immutable), // but widens it to string with let (reassignable).這一行代碼蘊(yùn)含了兩條關(guān)鍵規(guī)則當(dāng)使用const聲明時(shí)變量不可重新賦值因此 TypeScript 可以把它收窄narrow到最精確的字面量類(lèi)型x當(dāng)使用let聲明時(shí)變量之后可以被重新賦值因此 TypeScript 會(huì)把類(lèi)型放大widen為更寬泛的string。在 exploring-the-type-system.md西語(yǔ)版第 607 行起中文檔進(jìn)一步明確了 TypeScript 會(huì)在以下四類(lèi)場(chǎng)景自動(dòng)推斷類(lèi)型變量的初始化類(lèi)成員的初始化參數(shù)默認(rèn)值的推導(dǎo)函數(shù)返回類(lèi)型的推導(dǎo)。也就是說(shuō)推斷inference是 TypeScript 編譯器分析值或表達(dá)式后、基于已有信息得出類(lèi)型的過(guò)程它與我們下面要講的字面量類(lèi)型、類(lèi)型放大、const斷言等一系列機(jī)制環(huán)環(huán)相扣。二、字面量類(lèi)型推斷的最小單位要理解從值推斷類(lèi)型必須先理解字面量類(lèi)型Literal Types。字面量類(lèi)型是某個(gè)集合類(lèi)型中的單元素子集它定義一個(gè)非常精確的值而這個(gè)值本身是 JavaScript 的原始值primitive。TypeScript 中的字面量類(lèi)型包括字符串字面量、數(shù)字字面量和布爾字面量三種。參見(jiàn) literal-types.md 中的示例const a a; // String literal type字符串字面量類(lèi)型 const b 1; // Numeric literal type數(shù)字字面量類(lèi)型 const c true; // Boolean literal type布爾字面量類(lèi)型字面量類(lèi)型最常見(jiàn)的用途是與聯(lián)合類(lèi)型union配合構(gòu)成一個(gè)只接受固定取值集合的類(lèi)型別名。例如 literal-types.md 中的type O a | b | c;此時(shí)O只能取a、b、c這三個(gè)值中的任意一個(gè)任何其他字符串都會(huì)導(dǎo)致類(lèi)型錯(cuò)誤。這正是字面量類(lèi)型在聯(lián)合類(lèi)型、類(lèi)型守衛(wèi)type guards和類(lèi)型別名中發(fā)揮價(jià)值的場(chǎng)景?;氐絚onst x x因?yàn)閤不可變編譯器把它的類(lèi)型推斷為字面量x而let y y因?yàn)榭勺儽环糯鬄閟tring。這一點(diǎn)在 literal-inference.md字面量推斷中有完整對(duì)比const x x; // Literal type of x, because this value cannot be changed let y y; // Type string, as we can change this value三、類(lèi)型放大Widening為什么let會(huì)失去精確性從值推斷類(lèi)型中一個(gè)容易踩坑的環(huán)節(jié)是類(lèi)型放大。所謂放大是 TypeScript 給一個(gè)沒(méi)有顯式類(lèi)型注解、由初始化值推導(dǎo)類(lèi)型的變量分配類(lèi)型的過(guò)程——它允許從受限窄類(lèi)型走向更寬wide的類(lèi)型但反過(guò)來(lái)不行。exploring-the-type-system.md第 644 行起給出的放大示例非常直觀let x x; // TypeScript infers as string, a wide type let y: y | x y; // y types is a union of literal types y x; // Invalid Type string is not assignable to type x | y.這里x被放大為string而y的類(lèi)型是字面量聯(lián)合y | x。把寬泛的string賦給狹窄的字面量聯(lián)合編譯器會(huì)直接報(bào)錯(cuò)——放大的方向是單向的窄 → 寬不能逆向。放大還有一個(gè)更隱蔽的陷阱對(duì)象屬性的推斷默認(rèn)也是放大的。在 literal-inference.md 中文檔給出了一個(gè)非常經(jīng)典的生產(chǎn)級(jí)示例type X a | b; let o { x: a, // This is a wider string }; const fn (x: X) ${x}-foo; console.log(fn(o.x)); // Argument of type string is not assignable to parameter of type X盡管初始化時(shí)o.x的字面值是a但 TypeScript 認(rèn)為對(duì)象屬性在未來(lái)可以被重新賦值于是把它的類(lèi)型推斷為寬泛的string而不是字面量a。當(dāng)把o.x傳給形參類(lèi)型為X字面量聯(lián)合的函數(shù)fn時(shí)就觸發(fā)了Argument of type string is not assignable to parameter of type X錯(cuò)誤——string無(wú)法賦給更窄的a | b。這個(gè)例子是理解從值推斷類(lèi)型邊界的最佳教材推斷不是簡(jiǎn)單地照抄字面值而是結(jié)合可變性預(yù)期做出的保守判斷。四、解決問(wèn)題as const與類(lèi)型斷言對(duì)于上一節(jié)的對(duì)象屬性放大問(wèn)題literal-inference.md 給出了兩種標(biāo)準(zhǔn)解法。方案一使用const類(lèi)型斷言as constlet o { x: a as const, };as const告訴編譯器把這個(gè)值當(dāng)作不可變字面量處理不要放大。此時(shí)o.x的類(lèi)型就是字面量a可以安全地傳給fn。方案二斷言為具體類(lèi)型Xlet o { x: a as X, };直接把屬性斷言為字面量聯(lián)合X同樣能讓o.x滿(mǎn)足fn的參數(shù)約束。關(guān)于as const的更多用法exploring-the-type-system.md第 701 行起進(jìn)行了系統(tǒng)展開(kāi)作用于單個(gè)屬性const v { x: 3 as const, }; v.x 3;作用于整個(gè)對(duì)象深度只讀const v { x: 1, y: 2, } as const;配合元組tuple使用效果尤其突出const x [1, 2, 3]; // number[] const y [1, 2, 3] as const; // Tuple of readonly [1, 2, 3]同樣的數(shù)組字面量不加斷言推斷為可變的number[]加了as const則得到只讀元組readonly [1, 2, 3]——元素的字面量精度和不可變性都被完整保留。五、進(jìn)階const修飾符與泛型類(lèi)型參數(shù)TypeScript 5.0除了as constTypeScript 5.0 開(kāi)始支持在泛型參數(shù)上使用const修飾符讓編譯器推斷出最精確的類(lèi)型。這是從值推斷類(lèi)型在泛型場(chǎng)景下的直接延伸。exploring-the-type-system.md第 675 行起給出了對(duì)比示例。不使用const時(shí)屬性被放大為stringfunction identityT(value: T) { // No const here return value; } const values identity({ a: a, b: b }); // Type inferred is: { a: string; b: string; }使用const后屬性被保留為字符串字面量function identityconst T(value: T) { // Using const modifier on type parameters return value; } const values identity({ a: a, b: b }); // Type inferred is: { a: a; b: b; }同樣的函數(shù)調(diào)用普通泛型推斷出{ a: string; b: string }而const T版本能精確到{ a: a; b: b }。當(dāng)你需要保留傳入?yún)?shù)的精確字面量信息時(shí)例如構(gòu)建配置對(duì)象、路由表、常量映射這個(gè)特性非常實(shí)用。注意const修飾符作用于類(lèi)型參數(shù)需要 TypeScript 5.0 或更高版本。六、const關(guān)鍵字本身聲明級(jí)收窄除了as const與泛型const聲明變量的const關(guān)鍵字本身也是一種從值推斷類(lèi)型時(shí)的收窄手段。exploring-the-type-system.md第 660 行起指出用const聲明變量會(huì)得到更受限的類(lèi)型推斷。const x x; // TypeScript infers the type of x as x, a narrower type let y: y | x y; y x; // Valid: The type of x is inferred as x與第 3 節(jié)的放大例子對(duì)比當(dāng)x用const聲明后其類(lèi)型是字面量x因此y x合法而用let聲明時(shí)x被放大為string賦值就會(huì)報(bào)錯(cuò)。可見(jiàn)**能否精確推斷本質(zhì)上取決于變量是否可能被重新賦值**——這正是const與let在推斷結(jié)果上產(chǎn)生差異的根源。七、從函數(shù)返回值推斷類(lèi)型Type from Func Return從值推斷類(lèi)型在函數(shù)層面的體現(xiàn)是返回類(lèi)型推斷TypeScript 根據(jù)函數(shù)實(shí)現(xiàn)自動(dòng)推導(dǎo)其返回類(lèi)型無(wú)需顯式注解。這與本文主題同屬基于值的推斷家族原書(shū)在相鄰章節(jié) type-from-func-return.md 中有專(zhuān)門(mén)講解const add (x: number, y: number) x y; // TypeScript can infer that the return type of the function is a number這里add的返回類(lèi)型被自動(dòng)推斷為number。函數(shù)返回類(lèi)型推斷的適用范圍很廣表達(dá)式函數(shù)體直接取表達(dá)式類(lèi)型塊函數(shù)體則取return語(yǔ)句類(lèi)型并在存在多個(gè)返回路徑時(shí)合并為聯(lián)合類(lèi)型。結(jié)合第 2 節(jié)的推斷場(chǎng)景列表返回類(lèi)型推斷正是類(lèi)型推斷四大場(chǎng)景中最常用的一環(huán)。八、與顯式類(lèi)型注解的配合Type Annotations從值推斷類(lèi)型的目標(biāo)是讓編譯器自己算出類(lèi)型但這并不意味著要完全放棄注解。type-annotations.md 系統(tǒng)說(shuō)明了何時(shí)該依賴(lài)推斷、何時(shí)該顯式注解變量注解是可選的const x: number 1;由于 TypeScript 對(duì)簡(jiǎn)單類(lèi)型的推斷非常準(zhǔn)確大多數(shù)情況下這類(lèi)注解并不必要。函數(shù)參數(shù)注解通常必不可少function sum(a: number, b: number) { return a b; }箭頭函數(shù)lambda同樣支持參數(shù)注解const sum (a: number, b: number) a b;有默認(rèn)值的參數(shù)可以省略注解const sum (a 10, b: number) a b;默認(rèn)值讓編譯器可以從10推斷出a的類(lèi)型為number。返回類(lèi)型注解可以顯式寫(xiě)出const sum (a 10, b: number): number a b;對(duì)復(fù)雜函數(shù)先寫(xiě)返回類(lèi)型再寫(xiě)實(shí)現(xiàn)能幫你把函數(shù)契約想清楚是提升代碼可讀性的重要手段。原文檔還給出了一條非常實(shí)用的工程準(zhǔn)則在 type-annotations.md 結(jié)尾一般來(lái)說(shuō)考慮注解類(lèi)型簽名type signatures但不要注解函數(shù)體內(nèi)部的局部變量并且始終為對(duì)象字面量添加類(lèi)型。這條準(zhǔn)則的精髓在于讓編譯器在它擅長(zhǎng)的地方局部變量、簡(jiǎn)單值充分發(fā)揮推斷能力而在契約邊界函數(shù)簽名、對(duì)象字面量顯式聲明類(lèi)型從而兼顧簡(jiǎn)潔性與可維護(hù)性。關(guān)于顯式注解控制放大exploring-the-type-system.md第 730 行起還補(bǔ)充了用字面量聯(lián)合注解來(lái)精確控制對(duì)象屬性的手法const v: { x: 1 | 2 | 3 } { x: 1, // x is now a union of literal types: 1 | 2 | 3 }; v.x 3; // Valid v.x 100; // Invalid通過(guò)顯式注解{ x: 1 | 2 | 3 }v.x被限定為數(shù)字字面量聯(lián)合賦值100會(huì)直接報(bào)錯(cuò)——注解與推斷互為補(bǔ)充共同構(gòu)成從值/到類(lèi)型的完整控制手段。九、實(shí)踐總結(jié)從值推斷的決策要點(diǎn)綜合原文檔 type-from-value.md 及其關(guān)聯(lián)章節(jié)可提煉出以下實(shí)戰(zhàn)要點(diǎn)場(chǎng)景推斷結(jié)果依據(jù)與手段const x x字面量類(lèi)型xconst不可變 → 不放大見(jiàn) literal-inference.mdlet y y寬泛類(lèi)型stringlet可重新賦值 → 放大widening對(duì)象屬性o.x astring即使值看起來(lái)是字面量屬性被認(rèn)為可改變 → 放大需要精確字面量a或a \| bas const斷言或as X斷言泛型參數(shù)保留字面量{ a: a; b: b }TS 5.0 的const T類(lèi)型參數(shù)修飾符數(shù)組/元組需要精確類(lèi)型readonly [1, 2, 3]整體as const函數(shù)返回類(lèi)型自動(dòng)推斷如number返回類(lèi)型推斷見(jiàn) type-from-func-return.md核心心法可以濃縮為一句話類(lèi)型推斷的精確度取決于可變性預(yù)期——不可變const、as const、const T則保留字面量精度可變let、對(duì)象屬性則被放大為寬泛類(lèi)型。在此基礎(chǔ)上用顯式注解約束契約邊界函數(shù)簽名、對(duì)象字面量就能寫(xiě)出既簡(jiǎn)潔又安全的 TypeScript 代碼。延伸閱讀本文核心出處type-from-value.md西語(yǔ)版 與 type-from-value.md英語(yǔ)原版字面量類(lèi)型literal-types.md西語(yǔ)版 / literal-types.md英語(yǔ)版字面量推斷與as const修復(fù)合集literal-inference.md西語(yǔ)版 / literal-inference.md英語(yǔ)版推斷、放大、const與顯式注解的系統(tǒng)講解exploring-the-type-system.md西語(yǔ)版函數(shù)返回類(lèi)型推斷type-from-func-return.md西語(yǔ)版 / type-from-func-return.md英語(yǔ)版顯式類(lèi)型注解的最佳實(shí)踐type-annotations.md西語(yǔ)版 / type-annotations.md英語(yǔ)版原始值類(lèi)型基礎(chǔ)primitive-types.md英語(yǔ)版贊分享文檔教程【免費(fèi)下載鏈接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.項(xiàng)目地址https://gitcode.com/gh_mirrors/typ/typescript-book點(diǎn)擊查看免費(fèi)下載相關(guān)推薦TypeScript 從值推斷類(lèi)型Type from Value類(lèi)型推斷、字面量寬度化與 as const 實(shí)戰(zhàn)解析TypeScript 從值推斷類(lèi)型Type from Value類(lèi)型推斷、字面量寬度化與 as const 實(shí)戰(zhàn)解析 導(dǎo)讀 本文圍繞 The Conci文檔教程The Concise TypeScript Book從值推導(dǎo)類(lèi)型Type from Value——TypeScript 類(lèi)型推斷機(jī)制與實(shí)戰(zhàn)The Concise TypeScript Book從值推導(dǎo)類(lèi)型Type from Value——TypeScript 類(lèi)型推斷機(jī)制與實(shí)戰(zhàn) 導(dǎo)讀 本篇文檔教程TypeScript 類(lèi)型收窄Narrowing實(shí)戰(zhàn)指南從聯(lián)合類(lèi)型到精確類(lèi)型推斷TypeScript 類(lèi)型收窄Narrowing實(shí)戰(zhàn)指南從聯(lián)合類(lèi)型到精確類(lèi)型推斷 本文基于開(kāi)源書(shū)籍《The Concise TypeScript Book文檔教程上一篇OpenTSDB與InfluxDB終極對(duì)比如何選擇最適合的時(shí)間序列數(shù)據(jù)庫(kù)下一篇Python數(shù)據(jù)采集教程DataAnalysisInAction項(xiàng)目微博自動(dòng)化運(yùn)營(yíng)實(shí)現(xiàn)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考