TypeScript 常用的新玩法
大家好,我是若川。持續(xù)組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學(xué)習(xí)200行左右的源碼,共同進(jìn)步。同時極力推薦訂閱我寫的《學(xué)習(xí)源碼整體架構(gòu)系列》?包含20余篇源碼文章。歷史面試系列
上周分享了 ts 入門以及常用的小技巧《TS 在項目中的 N 個實用小技巧 - 文字稿》,然后發(fā)現(xiàn)有好幾個關(guān)注了公眾號來提問的(結(jié)果我開了小冰的自動回復(fù),有了以下奇怪的對話
當(dāng)看到想要回復(fù)的時候,發(fā)現(xiàn)...(怪我沒有開通知,略微尷尬?~~?😷
那就只能發(fā)文來講一講了(希望對應(yīng)的小伙伴能看到)?;仡櫹轮暗念}目,問怎么能讓他的返回結(jié)果是 string
const?user?=?{name:?'amy',?age:?18} function?getPersonInfo(key:?keyof?typeof?user)?{return?user[key]; }const?userName?=?getPersonInfo('name');?//?string?|?number解決方法肯定是泛型。這里需要關(guān)注的一個點是,泛型是可以只定義傳參不傳的,例如下文的 T extends keyof UserType 就限定了 T 一定是 user 中的一個 key,這個時候?qū)?shù)的類型定義定義成 T ,那么返回類型自然是 UserType[T] 了,這里返回類型不定義也成,ts 能根據(jù)下面的寫法自動推斷出來。這種通過泛型結(jié)合 extends 的寫法,可以一定情況下來輔助指定參數(shù)的類型。
const?user?=?{name:?'amy',?age:?18} type?UserType?=??typeof?userfunction?getPersonInfo<T?extends?keyof?UserType>(key:?T):?UserType[T]?{return?user[key]; }const?userName?=?getPersonInfo('name');?//?string專門開了篇文章,那肯定得寫點什么。上一篇文章做 ts 的分享的時候,發(fā)現(xiàn)市面上大多文章都是基于 ts3.x 的版本去做分析講解的,就算高級進(jìn)階篇,很多也只是講到一些常用的工具函數(shù)就戛然而至。甚至 google 搜索到的位于搜索引擎的 ts 中文網(wǎng)(據(jù)接觸,有不少有中文文檔就看中文文檔的小伙伴),也只是更新到 3.1,從 npm 的發(fā)布記錄來看也是四年前的版本了。所以,來寫點大家說得相對少的,但是我們?nèi)粘R部梢愿兄叫峦嬉獍蓗~
正文開始
幾個對 ECMAScript 提案的跟進(jìn)
一、可選操作鏈和空值合并
在 es2020 中,新增了一個深受大家喜愛的屬性:proposal-optional-chaining ,通常來說我們要使用需要結(jié)合 babel 配合轉(zhuǎn)譯來兼容低版本的瀏覽器(使用 @babel/preset-env ?的 ES2020 版本,或者使用 @babel/plugin-proposal-optional-chaining 插件。
另外還有一個運算符 ?? 空值合并(nullish coalescing operator)。例如 a ?? b 可以等同于 (a !== null && a !== undefined) ? a : b; 這個在做一些數(shù)據(jù)接口校驗的時候有些作用。
在 typescript 3.7 版本中,針對上述說的兩種操作符都及時做了支持,也就意味著如果你只使用了 typescript ,而沒使用 babel ?的場景也可以用它來玩(場景不多見,知道有這么回事就好)
let?x?=?foo?.bar.baz(); //?=>?let?x?=?foo?===?null?||?foo?===?void?0???void?0?:?foo.bar.baz();let?x?=?foo????bar(); //?let?x?=?foo?!==?null?&&?foo?!==?void?0???foo?:?bar();二、私有字段(Private Fields)
在 typescirpt 3.8 中支持使用 # 表示私有字段,另外在 4.3 版本中也支持了方法和 getter 都能有類似的寫法。demo 如下:
class?Person?{#name:?stringconstructor(name:?string)?{this.#name?=?name;}#someMethod()?{//...}get?#someValue()?{return?100;} }let?person?=?new?Person('Amy'); person.#name //?Property?'#name'?is?not?accessible?outside?class?'Person'其實跟 private 關(guān)鍵詞差不多,不同的點在于上述代碼,如果使用的是 private 屬性,你通過 person['name'] 這種手段還是可以訪問到,而你使用 person['#name'] 依然會報錯
三、短路運算符
三個運算符新增 *= 的操作:&&= 、?||= ?和 ???=
跟常見的 let a += a+1 的感覺差不多,只不過這里的操作運算符是 && || 和 ?? 而已,一個實際 demo,下面三種寫法都是一個意思。
const?a?=?{?duration:?50,?title:?''?};a.duration?||=?10;?//?demo1,?=>?50a.duration?=?a.duration?||?10;?//?demo2,?=>?50if?(!a.duration)?{?//?demo3,?=>?50a.duration?=?10;? }語言特性的優(yōu)化
一、Type-Only Imports and Export
翻譯過來,就是僅僅導(dǎo)入導(dǎo)出 type 。有一些用 ts 的小伙伴可能經(jīng)常會看到一些warning 提示,找不到 xx 定義。但是點進(jìn)文件一看,那些定義都好端端的寫在文件中,于是一頭霧水甚至直接忽略 warning 提示了。
這其實是該功能會解決的一個問題,舉一個例子來說明這情況產(chǎn)生的原因:
//?types.ts export?type?User?=?{...?}; export?type?UserList?=?User[];//?index.ts export?{?User,?UserList?}?from?'./types';?//?ts?types export?{?getUser,?CreateUser?}?from?'./user';?//?js?function從邏輯上看上面的代碼并沒有任何問題,但是在底層,這是一個被稱之為「導(dǎo)入省略」的功能起的作用。通常 babel 在編譯的時候,是一個個處理文件的,針對 ts 他一般是先刪除類型,然后再進(jìn)行編譯。我們?nèi)绻饪?index.ts ,實際都并不知道 User ?和 ?CreateUser 誰是一個 ts type 的定義而誰是 js 運行時需要的東西。于是 babel 只能被迫的將所有東西都保留,于是轉(zhuǎn)譯后的文件為
//?types.js --?empty?file?--//?index.js export?{?User,?UserList?}?from?'./types';?//?ts?types export?{?getUser,?CreateUser?}?from?'./user';?//?js?function而在 typescript 3.8 之后,我們的解決方法可以變成下述寫法。針對 type 的導(dǎo)入或者導(dǎo)出,babel會在刪除類型的環(huán)節(jié),直接將 import type ... 或者 export type xxx 這類的語句直接去掉。
//?index.ts export?type?{?User,?UserList?}?from?'./types';?//?ts?types export?{?getUser,?CreateUser?}?from?'./user';?//?js?function//?=>?babel?轉(zhuǎn)換后 export?{?getUser,?CreateUser?}?from?'./user';?//?only?js?function另外,在 4.5 的版本中,支持了對于某個變量局部使用 type 的寫法,就不用說類型和 js 的函數(shù)要拆成兩條語句了
//?ts?3.8 import?type?{?BaseType?}?from?"./some-module.js"; import?{?someFunc?}?from?"./some-module.js";//?=>?ts?4.5 import?{?someFunc,?type?BaseType?}?from?"./some-module.js";二、模版字符串
跟 es6 的模版字符串類似,不過是用于類型。此外,用在模板字符串類型中的泛型或類型別名,類型必須滿足是string | number | bigint | boolean | null | undefined之一(也就是基礎(chǔ)類型)。
應(yīng)該有不少小伙伴都聽說過,知乎上 ts 體操也是慢慢的從這特性出來開始越來越火。實際應(yīng)用個人覺得會更多對于一些需要字符串拼接的場景,減少枚舉。這里簡單的列舉一下例子
2.1 字符串組合場景
以下是一個 antd 中的 tootoolTip 組件,他有 12 個方向,傳統(tǒng)寫法,我們可能會直接枚舉 12 種,寫起來有那么一丟丟累,而且還很容易手抖不小心拼錯。
結(jié)合字符串模版和首字母大寫的 Capitalize 方法,我們可以將純枚舉羅列,變成以下的組合:
2.2 跟 infer 結(jié)合解析路由參數(shù)
網(wǎng)上看到的,話不多說,直接上代碼。將 :id 轉(zhuǎn)成 {id: string},不是特別理解的可以復(fù)習(xí)復(fù)習(xí) infer 然后多看幾眼自己嘗試寫一寫。
既然路由參數(shù)可以解析,那么 url 參數(shù)解析其實同理,想要將 a=1&b=2 轉(zhuǎn)換成?{ a:'1', b:'2' } 的話,自己擼的一個小思路:
另外還有一個在 map 中使用 as rename 的方法,結(jié)合模版語法,我們可以在寫一些通用函數(shù)的時候偷偷懶
type?Getters<T>?=?{[K?in?keyof?T?as?`get${Capitalize<string?&?K>}`]:?()?=>?T[K] };interface?Person?{name:?string;age:?number; }type?PersonGetters?=?Getters<Person> /*?=>?{getName:?()?=>?string;getAge:?()?=>?number; }?*/再有,通過字符串變量, lodash 的 get 方法也可以更加精準(zhǔn)的定義,還有 vuex 的模版等等。在 TSconf2020 中 anders 也給了很多不錯的例子在 github 上,有興趣的可以自行查閱:https://github.com/ahejlsberg/tsconf2020-demos/blob/master/template/main.ts??傊?#xff0c;就很多很多可以玩的玩法可以探索的,只要愿意。
三、解構(gòu)變量可以顯式標(biāo)記為未使用
使用解構(gòu)的用法時,如果我們只需要第二個參數(shù),而不需要第一個參數(shù)時,以前 ts 的語法檢查總是會報錯。在 typescript 4.2 版本之后,可以使用 _ 可以告訴 ts 這解構(gòu)變量標(biāo)記是未使用的,比如以下例子,只會報 second 沒有被使用。
function?getValues()?{return?['a',?'b']; } const?[_first,?second]?=?getValues(); //?已聲明“second”,但從未讀取其值。一個注意事項,如果你使用了 typescript-eslint 那可能編輯器的 eslint 檢查還是會提示錯誤,需要配置讓 no-unused-vars 規(guī)則允許下劃線的變量不被使用。
rules:?{"@typescript-eslint/no-unused-vars":?["error",?{?"ignoreRestSiblings":?true?}] },四、新增 Await 關(guān)鍵字
在 4.5 版本中支持,相當(dāng)于可以快速獲取 promise 的返回值了,結(jié)合 typeof 使用,或許可以節(jié)省幾句對類型的 import。
const?a?=?Promise.resolve('100') //?A?=?string type?A?=?Awaited<typeof?a>; //?B?=?number type?B?=?Awaited<Promise<Promise<number>>>; //?C?=?boolean?|?number type?C?=?Awaited<boolean?|?Promise<number>>;最后
除了上述的一些描述,ts 每次更新當(dāng)然也會有很多例如編譯速度提升啊,更加符合 js 邏輯的一些自動推導(dǎo)的優(yōu)化等等,這里就不做過多概述。還有一些配置項的新增,有興趣的小伙伴可以自行查閱官方文檔~~
相關(guān)回顧
1、TS 在項目中的 N 個實用小技巧 - 文字稿
生活總結(jié)
1、分享-前端小白的成長歷程文字稿
2、2021 總結(jié) | 鰻魚 - 平凡的生活
3、2020 總結(jié) | 鰻魚 - 一起來吃鰻魚飯吧
4、2019 總結(jié) | 鰻魚 - 寫在 24 歲門口的自己
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高?!,F(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結(jié),已經(jīng)堅持寫了8年,點擊查看年度總結(jié)。
同時,最近組織了源碼共讀活動,幫助3000+前端人學(xué)會看源碼。公眾號愿景:幫助5年內(nèi)前端人走向前列。
掃碼加我微信 ruochuan02、拉你進(jìn)源碼共讀群
今日話題
略。分享、收藏、點贊、在看我的文章就是對我最大的支持~
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的TypeScript 常用的新玩法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性时间选择—寻找第k小的数(分治算法)
- 下一篇: [html] iframe父页面如何获