自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

什么是 TypeScript 4.1 中的模板字面類型?

開發(fā) 后端
寫了這么多年 TypeScript,最大的感觸就是它非常易于理解——特別是對于具有 Java 背景的人。 但是,在聽說了 TypeScript 4.1(該語言最近的重大更新)的新聞之后,我還是為新鮮的特性感到驚奇。

[[358653]]

 寫了這么多年 TypeScript,最大的感觸就是它非常易于理解——特別是對于具有 Java 背景的人。 但是,在聽說了 TypeScript 4.1(該語言最近的重大更新)的新聞之后,我還是為新鮮的特性感到驚奇。

我不認為我是個無知的例外。 在利用該新聞作為機會來深入了解類型系統(tǒng)的實際工作方式之后,我想與您分享新版本的令人興奮的功能和變化,并提供關(guān)鍵字說明和許多神奇的示例。

如果你的 TypeScript 語言基礎(chǔ)比較扎實,并且渴望學(xué)習(xí)高級功能,那么就開始吧。

新的語言特性

模板字面類型

自 ES6 開始,我們就可以通過模板字面量(Template Literals)的特性,用反引號來書寫字符串,而不只是單引號或雙引號:

  1. const message = `text`; 

正如 Flavio Copes 所言,模板字面量提供了之前用引號寫的字符串所不具備的特性:

  • 定義多行字符串非常方便
  • 可以輕松地進行變量和表達式的插值
  • 可以用模板標簽創(chuàng)建 DSL(Domain Specific Language,領(lǐng)域特定語言)

模板字面量類型和 JavaScript 中的模板字符串語法完全一致,只不過是用在類型定義里面:

  1. type Entity = 'Invoice'
  2.  
  3. type Notification = `${Entity} saved`; 
  4. // 等同于 
  5. // type Notification = 'Invoice saved'
  6.  
  7.  
  8. type Viewport = 'md' | 'xs'
  9. type Device = 'mobile' | 'desktop'
  10.  
  11. type Screen = `${Viewport | Device} screen`; 
  12. // 等同于下面這一行 
  13. // type Screen = 'md screen' | 'xs screen' | 'mobile screen' | 'desktop screen'

當(dāng)我們定義了一個具體的字面量類型時,TypeScript 會通過拼接內(nèi)容的方式產(chǎn)生新的字符串字面量類型。

鍵值對類型中鍵的重新映射(Key Remapping)

映射類型可以基于任意鍵創(chuàng)建新的對象類型。 字符串字面量可以用作映射類型中的屬性名稱:

  1. type Actions = { [K in 'showEdit' | 'showCopy' | 'showDelete']?: boolean; }; 
  2. // 等同于 
  3. type Actions = { 
  4.   showEdit?:   boolean, 
  5.   showCopy?:   boolean, 
  6.   showDelete?: boolean 
  7. }; 

如果你想創(chuàng)建新鍵或過濾掉鍵,TypeScript 4.1 允許你使用新的 as 子句重新映射映射類型中的鍵:

  1. type MappedTypeWithNewKeys<T> = { 
  2.     [K in keyof T as NewKeyType]: T[K] 
  3.      

TypeScript Remapping KeysThe new as clause lets you leverage features like template literal types to easily create new property names based on old ones. Keys can be filtered by producing never so that you don’t have to use an extra Omit helper type in some cases: 通過使用新的 as 子句,我們可以利用模板字面量類型之類的特性輕松地基于舊屬性創(chuàng)建新屬性名稱。我們可以通過輸出 never 來過濾鍵,這樣在某些情況下就不必使用額外的 Omit 輔助類型:

  1. type Getters<T> = { 
  2.     [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] 
  3. }; 
  4.  
  5. interface Person { 
  6.     name: string; 
  7.     age: number; 
  8.     location: string; 
  9.  
  10. type LazyPerson = Getters<Person>; 
  11. //   ^ = type LazyPerson = { 
  12. //       getName: () => string; 
  13. //       getAge: () => number; 
  14. //       getLocation: () => string; 
  15. //   } 
  16.  
  17. // 去掉 'kind' 屬性 
  18. type RemoveKindField<T> = { 
  19.     [K in keyof T as Exclude<K, "kind">]: T[K] 
  20. }; 
  21.  
  22. interface Circle { 
  23.     kind: "circle"
  24.     radius: number; 
  25.  
  26. type KindlessCircle = RemoveKindField<Circle>; 
  27. //   ^ = type KindlessCircle = { 
  28. //       radius: number; 
  29. //   } 

TypeScript 利用帶有 as 子句的模板文字類型 (source)

JSX 工廠函數(shù)

JSX 代表 JavaScript XML,它允許我們使用 JavaScript 編寫 HTML 元素并將其放置在 DOM 中,而無需任何 createElement() 或 appendChild() 方法,例如:

  1. const greeting = <h4>Yes I can do it!</h4>; 
  2. ReactDOM.render(greeting, document.getElementById('root')); 

  TypeScript 4.1 通過編譯器選項 jsx 的兩個新選項支持 React 17 的 jsx 和 jsxs 工廠函數(shù):

  • react-jsx
  • react-jsxdev

“這些選項分別用于生產(chǎn)和開發(fā)編譯。通常,一個選項可以擴展自另一個選項。” — TypeScript發(fā)版說明

以下是兩個用于生產(chǎn)和開發(fā)的 TypeScript 配置文檔的兩個示例:

  1. // ./src/tsconfig.json 
  2.   "compilerOptions": { 
  3.     "module""esnext"
  4.     "target""es2015"
  5.     "jsx""react-jsx"
  6.     "strict"true 
  7.   }, 
  8.   "include": ["./**/*"

開發(fā)配置:

  1. // ./src/tsconfig.dev.json 
  2.   "extends""./tsconfig.json"
  3.   "compilerOptions": { 
  4.     "jsx""react-jsxdev" 
  5.   } 

如下圖所示,TypeScript 4.1 支持在像 React 這樣的 JSX 環(huán)境中進行類型檢查:

遞歸條件類型

另一個新增功能是遞歸條件類型,它允許它們在分支中引用自己,從而能夠更靈活地處理條件類型,使得編寫遞歸類型別名更加容易。下面是一個使用 Awaited 展開深層嵌套的 Promise 的示例:

  1. type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T; 
  2.  
  3. // 類似 `promise.then(...)`, 但是在類型上更加精確 
  4. declare function customThen<T, U>( 
  5.     p: Promise<T>, 
  6.     onFulfilled: (value: Awaited<T>) => U 
  7. ): Promise<Awaited<U>>; 

但是應(yīng)當(dāng)注意的是,TypeScript 需要更多時間來進行遞歸類型的類型檢查。Microsoft 警告,應(yīng)以負責(zé)任的態(tài)度謹慎使用它們。

Checked indexed accesses 索引訪問檢查

_ TypeScript 中的索引簽名允許可以像下面的 Options 接口中那樣訪問任意命名的屬性:

  1. interface Options { 
  2.   path: string; 
  3.   permissions: number; 
  4.  
  5.   // Extra properties are caught by this index signature. 
  6.   // 額外的屬性將被這個 
  7.   [propName: string]: string | number; 
  8.  
  9. function checkOptions(opts: Options) { 
  10.   opts.path; // string 
  11.   opts.permissions; // number 
  12.  
  13.   // 這些都可以!因為類型都是 string | number 
  14.   opts.yadda.toString(); 
  15.   opts["foo bar baz"].toString(); 
  16.   opts[Math.random()].toString(); 

在這里,我們看到不是 path 以及 permissions 的屬性應(yīng)具有 string | number 類型:

TypeScript 4.1 提供了一個新的標志 --noUncheckedIndexedAccess,使得每次屬性訪問(如 opts.path)或索引訪問(如 opts [“ blabla”] )都可能未定義。這意味著如果我們需要訪問上一個示例中的 opts.path 之類的屬性,則必須檢查其是否存在或使用非 null 斷言運算符(后綴 ! 字符):

  1. function checkOptions(opts: Options) { 
  2.   opts.path; // string 
  3.   opts.permissions; // number 
  4.  
  5.   // 以下代碼在 noUncheckedIndexedAccess 開啟時是非法的 
  6.   opts.yadda.toString(); 
  7.   opts["foo bar baz"].toString(); 
  8.   opts[Math.random()].toString(); 
  9.  
  10.   // 檢查屬性是否真的存在 
  11.   if (opts.yadda) { 
  12.     console.log(opts.yadda.toString()); 
  13.   } 
  14.  
  15.   // 直接使用非空斷言操作符 
  16.   opts.yadda!.toString(); 

--noUncheckedIndexedAccess 標志對于捕獲很多錯誤很有用,但是對于很多代碼來說可能很嘈雜。 這就是為什么 --strict 開關(guān)不會自動啟用它的原因。

不需要 baseUrl 指定路徑

在 TypeScript 4.1 之前,要能夠使用 tsconfig.json 文件中的 paths,必須聲明 baseUrl 參數(shù)。 在新版本中,可以在不帶 paths 選項的情況下指定 baseUrl。 這解決了自動導(dǎo)入中路徑不暢的問題。

  1.     "compilerOptions": { 
  2.         "baseUrl""./src"
  3.         "paths": { 
  4.             "@shared": ["@shared/"] // This mapping is relative to "baseUrl" 
  5.         } 
  6.     } 

checkJs 默認打開 allowJs

如果您有一個 JavaScript 項目,正在其中使用 checkJs 選項檢查 .js 文件中的錯誤,則還應(yīng)該聲明 allowJs 以允許編譯 JavaScript 文件。而 TypeScript 4.1 中,默認情況下 checkJs 意味著 allowJs:

  1.   compilerOptions: { 
  2.     allowJs: true
  3.     checkJs: true 
  4.   } 

JSDoc @see 標簽的編輯器支持

在編輯器中使用 TypeScript 時,現(xiàn)在對 JSDoc 標簽 @see 有了更好的支持,這將改善TypeScript 4.1的可用性:

  1. // @filename: first.ts 
  2. export class C {} 
  3.  
  4. // @filename: main.ts 
  5. import * as first from "./first"
  6.  
  7. /** 
  8.  * @see first.C 
  9.  */ 
  10. function related() {} 

不兼容改變

lib.d.ts 變動

結(jié)構(gòu)和 DOM 的環(huán)境聲明,使您可以輕松地開始編寫經(jīng)過類型檢查的 JavaScript 代碼。

該文件自動包含在 TypeScript 項目的編譯上下文中。 您可以通過指定 --noLib 編譯器命令行標志或在 tsconfig.json 中配置 noLib 為 true 來排除它。

在 TypeScript 4.1 中,由于 DOM 類型是自動生成的,lib.d.ts 可能具有一組變動的 API,例如,從 ES2016 中刪除的 Reflect.enumerate。

abstract 成員不能被標記為 async

在另一個重大更改中,標記為 abstract 的成員不能被再標記為 async。 因此,要修復(fù)您的代碼,必須刪除 async 關(guān)鍵字:

  1. abstract class MyClass { 
  2.   // 在 TypeScript 4.1 中必須刪除 async 
  3.   abstract async create(): Promise<string>; 

any/unknown 向外傳播

在 TypeScript 4.1 之前,對于像 foo && somethingElse 這樣的表達式, foo 的類型是 any 或 unknown。 整個表達式的類型將是 somethingElse 的類型,在以下示例中就是 {someProp:string} :

  1. declare let foo: unknown; 
  2. declare let somethingElse: { someProp: string }; 
  3. let x = foo && somethingElse; 

在 TypeScript 4.1 中, any 和 unknown 都將向外傳播,而不是在右側(cè)傳播。通常,這個變更合適的解決方法是從 foo && someExpression 切換到 !!foo && someExpression。

  • 注意:雙重感嘆號(!!)是將變量強制轉(zhuǎn)換為布爾值(真或假)的一種簡便方法。

Promise 中 resolve 的參數(shù)不再是可選類型

Promise 中 resolve 的參數(shù)不再是可選的,例如下面的代碼:

  1. new Promise((resolve) => { 
  2.   doSomethingAsync(() => { 
  3.     doSomething(); 
  4.     resolve(); 
  5.   }); 
  6. }); 

這段代碼在 TypeScript 4.1 中編譯會報錯:

  1. resolve() 
  2.   ~~~~~~~~~ 
  3. error TS2554: Expected 1 arguments, but got 0. 
  4.   An argument for 'value' was not provided. 

要解決這個問題,必須在 Promise 中給 resolve 提供至少一個值,否則,在確實需要不帶參數(shù)的情況下調(diào)用 resolve() 的情況下,必須使用顯式的 void 泛型類型參數(shù)聲明 Promise:

  1. new Promise<void>((resolve) => { 
  2.   doSomethingAsync(() => { 
  3.     doSomething(); 
  4.     resolve(); 
  5.   }); 
  6. }); 

條件展開將會創(chuàng)建可選屬性

在 JavaScript 中,展開運算符 { ...files } 不會作用于假值,例如 files 為 null 或者 undefined。

在以下使用條件傳播的示例中,如果定義了 file,則將傳播 file.owner 的屬性。否則,不會將任何屬性傳播到返回的對象中:

  1. function getOwner(file?: File) { 
  2.   return { 
  3.     ...file?.owner, 
  4.     defaultUserId: 123, 
  5.   }; 

在TypeScript 4.1之前, getOwner 返回基于每個展開對象的聯(lián)合類型:

  1. { x: number } | { x: number, name: string, age: number, location: string } 
  • 如果定義了 file,則會擁有來自Person(所有者的類型)的所有屬性。
  • 否則,結(jié)果中一個都不會展示

但是事實證明,這樣的代價最終會變得非常高昂,而且通常無濟于事。在單個對象中存在數(shù)百個展開對象,每個展開對象都可能增加數(shù)百或數(shù)千個屬性。 為了更好的性能,在TypeScript 4.1中,返回的類型有時使用全部可選屬性:

  1.     x:         number; 
  2.     name?:     string; 
  3.     age?:      number; 
  4.     location?: string; 

不匹配的參數(shù)將不再關(guān)聯(lián)

過去,彼此不對應(yīng)的參數(shù)在 TypeScript 中通過將它們與 any 類型關(guān)聯(lián)而彼此關(guān)聯(lián)。

在下面的重載示例(為同一功能提供多種功能類型)中, pickCard 函數(shù)將根據(jù)用戶傳入的內(nèi)容返回兩個不同的內(nèi)容。如果用戶傳入表示 deck 的對象,則該函數(shù)將選擇 card。 如果用戶選擇了 card,他們將得到他們選擇的 card:

  1. let suits = ["hearts""spades""clubs""diamonds"]; 
  2.  
  3. function pickCard(x: { suit: string; card: number }[]): number; 
  4. function pickCard(x: number): { suit: string; card: number }; 
  5. function pickCard(x: any): any { 
  6.   // Check to see if we're working with an object/array 
  7.   // if so, they gave us the deck and we'll pick the card 
  8.   if (typeof x == "object") { 
  9.     let pickedCard = Math.floor(Math.random() * x.length); 
  10.     return pickedCard; 
  11.   } 
  12.   // Otherwise just let them pick the card 
  13.   else if (typeof x == "number") { 
  14.     let pickedSuit = Math.floor(x / 13); 
  15.     return { suit: suits[pickedSuit], card: x % 13 }; 
  16.   } 
  17.  
  18. let myDeck = [ 
  19.   { suit: "diamonds", card: 2 }, 
  20.   { suit: "spades", card: 10 }, 
  21.   { suit: "hearts", card: 4 }, 
  22. ]; 
  23.  
  24. let pickedCard1 = myDeck[pickCard(myDeck)]; 
  25. alert("card: " + pickedCard1.card + " of " + pickedCard1.suit); 
  26.  
  27. let pickedCard2 = pickCard(15); 
  28. alert("card: " + pickedCard2.card + " of " + pickedCard2.suit); 

使用 TypeScript 4.1,某些情況下賦值將會失敗,而某些情況下的重載解析則將失敗。解決方法是,最好使用類型斷言來避免錯誤。

最后一點想法

TypeScript 通過在運行代碼之前捕獲錯誤并提供修復(fù)程序來節(jié)省我們的時間。通過深入了解 TypeScript,我們可以更好地了解如何改善代碼結(jié)構(gòu),并得到解決復(fù)雜問題的方案。希望本文能夠幫助你探索類型系統(tǒng),并使您的編程旅程更加精彩。

TypeScript 4.1 可以通過 NuGet 或 NPM 獲?。?/p>

  1. npm install typescript 

  

 

責(zé)任編輯:姜華 來源: 圖雀社區(qū)
相關(guān)推薦

2021-10-09 07:10:30

Go字面量組合

2023-04-14 15:44:20

TypeScrip函數(shù)重載

2022-06-08 08:01:28

模板字面量類型

2022-04-10 19:26:07

TypeScript類型語法

2021-07-27 06:06:34

TypeScript語言運算符

2021-08-18 07:56:05

Typescript類型本質(zhì)

2022-04-11 08:42:09

TypeScript子類型定義

2024-05-11 10:19:31

TypeScript類型接口

2022-08-08 09:00:42

TypeScript映射類型

2021-06-09 07:55:19

Typescript類型檢查

2020-03-31 16:30:09

JS語言ES 6

2020-04-02 09:01:54

JSES 6開發(fā)

2022-03-14 08:33:09

TypeScriptJavaScript前端

2021-06-05 21:30:24

typescriptOverride檢查

2022-02-25 09:06:02

TypeScripnever工具

2024-08-12 08:50:17

2021-06-01 06:00:06

typescriptjavascript

2024-09-09 08:35:30

2024-08-22 10:51:09

Typescript場景類型

2022-09-20 14:43:55

TypeScript類型體操
點贊
收藏

51CTO技術(shù)棧公眾號