泛型在強(qiáng)類型多態(tài)組件中的應(yīng)用
復(fù)制粘貼一時(shí)爽,一直粘貼垃圾場。那一坨坨垃圾遲早得自己收拾,除非你比香港記者跑得還快。
? ? 在實(shí)際的業(yè)務(wù)中,動(dòng)態(tài)的數(shù)據(jù)類型和動(dòng)態(tài)組件以及組件的擴(kuò)展并不鮮見。比如你有多個(gè)不同類型的數(shù)據(jù),你希望以相同的方式展示;或者你在運(yùn)行時(shí)才能確定期望渲染哪個(gè)組件;又或者你想擴(kuò)展你的組件,使之行為根據(jù)不同的數(shù)據(jù)類型動(dòng)態(tài)化。
? ? 這時(shí)候,多態(tài)組件或許是你的最佳方案。多態(tài)組件是一種把一個(gè)組件的多種形態(tài)抽象為一個(gè)單一組件的技術(shù)。這樣,當(dāng)需要擴(kuò)展功能時(shí),只需要向該組件中添加新的形態(tài)即可。
? ? 一個(gè)簡單的多態(tài)組件類似這樣:
? ? 在這個(gè)例子中,cmp調(diào)用時(shí)可根據(jù)不同場景傳入各自想要的tagName和對(duì)應(yīng)的props。
? ? 下一步,你期望后續(xù)的代碼有關(guān)于類型的智能提示。比如tagName限定為原生html標(biāo)簽,當(dāng)cmp被調(diào)用,tagName傳值字符串a(chǎn)bc,你期望得到一個(gè)錯(cuò)誤提示:abc不是某某某的屬性;props各個(gè)屬性映射為對(duì)應(yīng)的element各個(gè)屬性,隨便什么阿貓阿狗也會(huì)有錯(cuò)誤提示。
? ? ?這就需要為tagName分配你期望的多種類型,并且在tagName和props之間建立約束關(guān)系。泛型正是為此而生。(如果你對(duì)泛型有所了解,或熟知泛型的優(yōu)勢,請往下劃過N個(gè)代碼片段直接看結(jié)論。)
? ? TypeScript 中的泛型是用來解決類型不確定的問題的特殊語法。泛型允許我們在定義一個(gè)函數(shù)、類或接口時(shí)不指定具體類型,并在使用這個(gè)函數(shù)、類或接口時(shí)指定具體類型。
? ? 一個(gè)簡單的泛型函數(shù)??:
? ? 一個(gè)靈活的多態(tài)組件如果添加了泛型,定義時(shí)便無需指定具體類型,使用時(shí)可以根據(jù)分配的類型得到期望的結(jié)果。
? ? 假設(shè)現(xiàn)在需要為html標(biāo)簽及其屬性創(chuàng)建約束。HTMLElementTagNameMap 是typescript內(nèi)建類型,源碼類似這樣:
? ? 定義所有的標(biāo)簽類型和標(biāo)簽對(duì)應(yīng)的Element對(duì)象:
? ? 給組件添加泛型約束:
? ??Vue 提供了一個(gè)?h()
?函數(shù)用于創(chuàng)建 vnodes。這是一種約定俗成的實(shí)現(xiàn)虛擬DOM的方式,用JavaScript來生成html標(biāo)記語言。它的第一參數(shù)是必填的,可以是html標(biāo)簽,也可以是自定義組件。接下來我們用 h( ) 完善這個(gè)具有強(qiáng)類型約束的動(dòng)態(tài)組件。?
????我們來寫幾個(gè)例子試試看這個(gè)類型約束是否生效:

? ??
? ? 根據(jù)vue3官網(wǎng)文檔:
component 是一個(gè)用于渲染動(dòng)態(tài)組件或元素的“元組件”。要渲染的實(shí)際組件由?
is
?prop 決定。is的值可以是字符串(htmlTag或者組件的注冊名稱),也可以直接綁定到組件。
? ? 在vue組件中的應(yīng)用,我們將 is 直接綁定到 Input 組件:
? ??看下效果:

? ? 通過以上步驟,我們初步實(shí)現(xiàn)了一個(gè)具有類型約束的多態(tài)組件,支持傳入html標(biāo)簽和屬性以便動(dòng)態(tài)渲染,并且能在使用時(shí)得到期望的錯(cuò)誤提示和結(jié)果。
? ? 在實(shí)際業(yè)務(wù)中,一個(gè)很常見的場景是我們往往還需要傳入自定義組件或開源組件庫的組件。接下來,讓我們來擴(kuò)展一下。
有兩個(gè)解決辦法,如果非得寫箭頭函數(shù)的話:
也可以這樣活用extends:
如果你的函數(shù)式組件泛型剛好需要extends 某個(gè)類型,這種方式可以說是恰到好處恰如其分的。
當(dāng)然,還可以不寫箭頭函數(shù):