'any' is cheap, show me the 'type'(Ⅱ)

引子
之前的
我們介紹了JS的靈活以及TS可以“管束”JS,那么TS是否能在“管束的同時(shí)”,還保留代碼的靈活呢?從?
的使用說起
?
的使用可以極大的保持你的代碼靈活,且避免 問題。舉個(gè)例子,我們之前聊到的菜單組件,我希望點(diǎn)擊每個(gè)菜單項(xiàng)時(shí),如果當(dāng)前菜單有綁定一個(gè)“onClick”方法就在每個(gè)菜單項(xiàng)點(diǎn)擊時(shí)執(zhí)行,沒有則忽略,類似這樣:

較好的做法就是把這個(gè)onClick
作為一個(gè)Menu這個(gè)props的可選屬性:
export interface MenuProps {
?onClick?: ?(selectIndex: string) => void
?/**other props */
?// ...
}
如此一來當(dāng)你在組件中需要處理onClick時(shí),如果這個(gè)屬性可能是undefined,Ts會(huì)提示你:

這樣就可以在開發(fā)中專注業(yè)務(wù),而將提示可能未處理xxx is not defined
的工作交給TS,當(dāng)然,這一切的前提是你對你的入?yún)傩杂星逦鷾?zhǔn)確的定義。
使用&
實(shí)現(xiàn)類型的聯(lián)合,搭配Partial
實(shí)現(xiàn)可選參數(shù)
我在上一篇文章中提到使用TS可以從定義入?yún)⒌膖ype和interface開始
,還提到了一個(gè)問題,如何保證我們自己編寫的button組件擁有onClick/onFocus等所有button的原生方法,以保證使用者可以無學(xué)習(xí)成本的使用它?全部實(shí)現(xiàn)一遍的方式過于麻煩,當(dāng)然,button的原生屬性、方法,React已經(jīng)幫我們準(zhǔn)備好了—— ,我們自定義的buttonProps只要全包含它即可,可以使用&
, 當(dāng)然,我們肯定希望這樣添加過來的原生屬性都是帶?
的可選屬性,這樣代碼就更靈活了,很簡單,使用Partial
即可:
interface BaseButtonProps {
?/** 設(shè)置按鈕樣式 */
?className?: string
?/** 設(shè)置按鈕禁用 */
?disabled?: boolean
?/** 設(shè)置按鈕大小 */
?size?: buttonSize
?/** 設(shè)置按鈕類型 */
?btnType?: buttonType
}
// 幫助當(dāng)前Button組件獲取諸如onClick方法等Button的原生屬性,方法
type NativeButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLElement>
// 將所有屬性均變?yōu)榭蛇x的,通過Partial實(shí)現(xiàn)
export type ButtonProps = Partial<NativeButtonProps>
這樣開發(fā)者使用時(shí),就和原生button的使用體驗(yàn)一模一樣了:

使用extends
實(shí)現(xiàn)接口的繼承,并通過Omit
實(shí)現(xiàn)排除
剛才舉的例子介紹了如何通過&
實(shí)現(xiàn)類型的“繼承”,你是否會(huì)好奇,繼承不是extends嗎?
當(dāng)然,也可以。
比如我們要開發(fā)Input組件,按上面說的思路,我們可以繼承React的InputHTMLAttributes,完全可以這樣寫:
type InputSize = 'lg' | 'sm'
export interface InputProps extends InputHTMLAttributes<HTMLElement> {
? ?// 自定義屬性
? ?/**
? * 設(shè)置input的size
? */
?size?: InputSize;
}
不過這樣代碼會(huì)報(bào)錯(cuò),是因?yàn)?code>InputHTMLAttributes中就有size這個(gè)屬性了,當(dāng)然你可以對你的自定義屬性size重命名,亦或者,使用Omit“排除”這個(gè)屬性,類似要求使用子類自身屬性,而不繼承父類特定屬性的意思

繼承到底有什么好
上面分享的一些TS技巧都是始自對函數(shù)/純函數(shù)中輸入屬性的類型限定,進(jìn)而實(shí)現(xiàn)代碼中的編碼提示,錯(cuò)誤檢查提示等。其實(shí)對一個(gè)函數(shù)/純函數(shù)的輸出,也可以限定。那就是通過ReturnType。很多類型,技巧,你也可以通過
了解更多。使用TS開發(fā)代碼的體驗(yàn)就要不停地和類型死磕,這樣的行為被稱為:類型體操
。如果你對這些類型的實(shí)現(xiàn)方式感興趣,可以看看 ,也希望大家在這些磨礪后,可以喊出那句——

迎面向我們走來的,是OpenTiny方陣
我們今天介紹的&
/extends
都跟“繼承”有點(diǎn)關(guān)系,那么,繼承到底有什么好?
最簡單的好處,他能減少你的重復(fù)代碼,比如上面說的button組件中,通過繼承React.ButtonHTMLAttributes無需實(shí)現(xiàn)onClick、onFocus等方法。當(dāng)然,更廣泛的說,很多復(fù)雜的組件,也是組合了多個(gè)簡單組件,那他們的屬性之間就一定可以通過繼承來簡化。比如一個(gè)AutoComplete組件,就是一個(gè)Input組件加一個(gè)Select組件。那它的props可能就是這樣:

當(dāng)然,你也可以把很多組件的公共屬性抽取出來,這樣可能還能進(jìn)一步簡化代碼,類似這樣:

或者這樣:

沒錯(cuò),這就是我們的TinyUI組件庫,Angular版本的設(shè)計(jì)理念,如今TinyUI也將正式開源,歡迎微信搜索我們的小助手: opentiny-official
,了解更多信息~