你可能沒用好 typescript
前言
最近在社區(qū)看到很多類似 typescript 不適合寫業(yè)務(wù)的言論,我覺得這些言論都是基于一些誤解,用好 typescript 對業(yè)務(wù)代碼的健壯性和可維護(hù)性是有很大幫助的,本文就來聊聊如何用好 typescript。
為什么你會覺得 typescript 不適合寫業(yè)務(wù)
我們就用后臺業(yè)務(wù)最常見的 Form,Table 頁面來聊聊,你為什么會覺得 typescript 不適合寫業(yè)務(wù)
image.png首先,對于這個常見的頁面,我們所有的查詢操作都是基于列表的查詢接口。而列表查詢接口所有的參數(shù),不管是 page, size 還是各種 filter 都會最終影響你表格數(shù)據(jù)的展示。
所以對于這類頁面最常見的一個操作就是把這些參數(shù)都放到 你的 deps 中,我們只需要改變 deps 中的值,就會自動觸發(fā) useEffect 請求數(shù)據(jù)。當(dāng)然,如果你使用了 swr react-query 這類請求庫,deps 就應(yīng)該換成 key。
下面我用 swr 一個常見的列表接口來舉例。
import?useSWR?from?'swr';
//?swr?傳了范型這里?axios?的輸入輸出可以不用寫,但是為了方便理解以及照顧不用?swr?的朋友,我還是寫了
//?不用?axios?的朋友換成自己項(xiàng)目的請求就好了
const?fetcher?=?([url,?params]:?[url:?string,?params:?ListParams])?=>?{
??return?req_get(url,?params).then((res)?=>?res.data);
};
function?useList(params:?ListParams)?{
??const?{data,?isLoading}?=?useSWR<ListOutput>(['/api/list',?params],?fetcher);
??return?{
????data:?data?.list,
????count:?data?.count,
????isLoading,
??};
}
可以看到,相比 javascript ,需要額外做的工作其實(shí)就是定義參數(shù)類型 ListParams 和接口返回的類型 ListOutPut。(ListParams 也是我們需要定義的 state 的類型)
只要定義好了輸入和輸出的類型,typescript 就會幫你做好類型檢查,并做好代碼提示。這樣你就不用擔(dān)心參數(shù)傳錯了,或者接口返回的數(shù)據(jù)類型不對了, 也不用擔(dān)心 data 為空的時候,出現(xiàn)以下常見的錯誤提示
Cannot?read?properties?of?undefined?(reading?'xxx')
很多人覺得 typescript 不適合寫業(yè)務(wù),我想是因?yàn)樗麄冇X得定義類型,特別是一些復(fù)雜的類型是一件很麻煩的事情。
如果體驗(yàn)過 tRPC , 或者 graphql-codegen 的話,你就會發(fā)現(xiàn),其實(shí)這些類型都是可以復(fù)用的。我們的后臺一般都是用強(qiáng)類型語言編寫的。他們在寫接口的時候,其實(shí)已經(jīng)定義好了這些類型,我們只需要把這些類型拿過來就好了。
但是我們大多數(shù)人的項(xiàng)目前后端都不是一個倉庫,也不是 graphql , 那么我們怎么拿到這些類型呢?
OpenAPI
OpenAPI規(guī)范(以前稱為Swagger規(guī)范)是一種機(jī)器可讀的接口定義語言規(guī)范,用于描述,生成,使用和可視化Web服務(wù)。它以前是Swagger框架的一部分,在2016年成為一個獨(dú)立的項(xiàng)目,由Linux基金會的一個開源協(xié)作項(xiàng)目OpenAPI Initiative監(jiān)督。
如果你的項(xiàng)目遵循 OpenAPI 規(guī)范,后臺會給你一個 swagger 文檔。那么恭喜你,你可以直接用 swagger 生成的 typescript 類型。
如果你在 github 上用 openapi , codegen , swagger 之類的關(guān)鍵詞搜索,你會發(fā)現(xiàn)有很多開源的工具可以幫你生成 typescript 類型。
甚至有很多項(xiàng)目會直接幫你生成接口,但是我覺得自動生成接口這種東西如果你自己用 node 寫一個類似的工具會更加符合你的業(yè)務(wù)需求。我們需要的僅僅是開箱即用,生成類型
生成類型
我就用我們項(xiàng)目中常用的 openapi-typescript 來舉例,選擇他的原因純粹是因?yàn)閴蚝唵?你可以自由選擇你要的工具。首先安裝
//?選擇 5.4.1 版本,原因后面會說。使用 npm 的自行翻譯一下
[email protected]
然后在 package.json 中配置
//沒有?prettier?的話,不要?--c?.prettierrc.js
{
??"scripts":?{
????"codegen":?"npx?openapi-typescript?這里你填你swagger.json的地址?--c?.prettierrc.js?--make-paths-enum???--output?./src/ApiInterface.ts",
??}
}
//?這里的?--make-paths-enum?是為了生成路徑的枚舉
//?最新版本去掉了這個功能,我覺得這個功能很實(shí)用,所以我選擇了?5.4.1?版本
然后我們每次運(yùn)行 yarn codegen 就可以生成 ApiInterface.ts 文件了。
以我們的一個真實(shí)項(xiàng)目為例子,首先我們來看生成的路徑枚舉
有了路徑枚舉我們就不需要自己寫路徑了,直接用枚舉就好了,這樣就不會出現(xiàn)路徑寫錯的問題了。

然后我們來看看生成的類型
可以看到我們主要想要的都是 components 下的 schemas 類型。像上個 gif 一樣,我們可以定義一個類型
import?{?type?components?}?from?'@/ApiInterface'
export?type?ApiInterface?=?components['schemas']
這樣,我們就不再需要自己來手動定義輸入輸出的類型了,就可以愉快的回車到底了

總結(jié)
這種方案雖然不如 tRPC 那樣直接復(fù)用一個類型,后臺只要更改類型,前端就會報(bào)錯。但是 tRPC 遷移的成本是很高的,而且很多公司的后臺都不是用 typescript 寫的,但是很多公司都會遵循 OpenAPI 規(guī)范。
如果后臺改了接口,只需要運(yùn)行一下 yarn codegen,編輯器就會自動給你提示哪些地方需要修改,你就會覺得 typescript 寫業(yè)務(wù)也是一件很愉快的事情了。
最后,希望本文能對你有所幫助,以上。
