最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Typescript 回調(diào)函數(shù)、事件偵聽(tīng)的類型定義與注釋

2023-03-13 07:14 作者:吳小敏63  | 我要投稿

實(shí)際項(xiàng)目中會(huì)運(yùn)到的 Typescript 回調(diào)函數(shù)、事件偵聽(tīng)的類型定義,如果剛碰到會(huì)一臉蒙真的,我就是

這是第一次我自己對(duì) Typescript 記錄學(xué)習(xí),所以得先說(shuō)一下我與 Typescript 的孽緣

記得最早是在2014年遇上 Typescript 當(dāng)時(shí)是完全看不上這東西的,甚至帶著鄙視的心態(tài),到不是因?yàn)樗仍?Js 要多寫(xiě)很多代碼而是

作為一名前端老兵遇上 Typescript 的語(yǔ)法與類型就會(huì)讓我想起剛工作時(shí)學(xué)習(xí)的 Flash Actionscript3.0 腳本時(shí)代。不能說(shuō)是完全相同,簡(jiǎn)直是一模一樣。

大約2006年 Adobe 的 flash 9 就開(kāi)發(fā)了自己的新腳本語(yǔ)言 ActionScript 3 完全符合 ECMAScript 第四版規(guī)范, 也就是ES4

與當(dāng)時(shí)代的 Javascript 還處于刀耕火種不同,在 Flash 編輯器中使用 ActionScript3 編寫(xiě)代碼就有了比較完善的類型檢測(cè)與類型提示。

曾經(jīng)的 Actionscript3.0 輝煌的時(shí)代,那時(shí)動(dòng)畫(huà)有Flash, 應(yīng)用有 Flex, 跨平臺(tái)桌面應(yīng)用有 Adobe air ,后面還支持移動(dòng)端,這些用的都是 Actionscript3.0 腳本

而 Actionscript3.0 在我熟練掌握后退出了歷史舞臺(tái)。。。多棒的腳本語(yǔ)言啊,我又白學(xué)了。原因大致是 Adobe 的不上進(jìn)和其它大公司的聯(lián)合圍剿

所以當(dāng)我第一次接觸到 Typescript 的時(shí)候內(nèi)心非常抵觸。

這幾年 Javascript 跟其它語(yǔ)言相比可能還差一大截,但已和當(dāng)年刀耕火種不同,前端工具與框架層出不窮,快速更新迭代 web 應(yīng)用越來(lái)越復(fù)雜,前端工具越來(lái)越成熟,Typescript 的應(yīng)用

也就水到渠成了。當(dāng)在團(tuán)隊(duì)中使用 Typescript 雖然多寫(xiě)了點(diǎn)兒類型代碼,但是好處太多了,可以說(shuō)是用了就回不去了

我們這樣的小角色怎能與時(shí)代洪流相抵呢,隨波逐流吧,學(xué)吧學(xué)到廢為止

如果你學(xué)過(guò) Actionscript3 那么對(duì) Typescript 中普通的,類、接口、繼承、變量類型等概念與語(yǔ)法就會(huì)非常熟悉

唯一沒(méi)有且用的比較廣泛的概念當(dāng)屬 Typescirpt 中的 "泛型" , 泛型的理解與運(yùn)用自我感覺(jué)是比較難的,但又不能不面對(duì),只能多看多學(xué)了

我所學(xué)到與理解的也是看的其它人分享的資料,拾人牙慧

最討厭別人寫(xiě)的文章、書(shū),上來(lái)就是一堆概念和名詞解釋。把你繞的云里霧里

我希望的是從實(shí)際運(yùn)用出發(fā),從問(wèn)題開(kāi)始找解決方案。也就是學(xué)了干啥用,得學(xué)以致用才能更好的理解

以下假設(shè)你已經(jīng)對(duì) Typescript 已經(jīng)有了一定的基礎(chǔ)了解

如果你從未學(xué)過(guò) Typescript 那么請(qǐng)退出先去學(xué)基礎(chǔ)!

一、回調(diào)函數(shù)的類型提示

注冊(cè)自定義事件,傳入的回調(diào)函數(shù),如果事件類型(事件名)對(duì)應(yīng)的回調(diào)函數(shù)內(nèi)回調(diào)參數(shù)不一樣

那么回調(diào)函數(shù)的類型注釋我們無(wú)能為力,只能用 any ,如下 addEvent 函數(shù),用于注冊(cè)事件

eventType 定義為 string 類型

listener 這個(gè)是函數(shù) Function, 但由于事件類型有多種,對(duì)應(yīng)的回調(diào)函數(shù)也有好多種

這就尬住了,暫時(shí)只能用 (...args: any[]) => any 來(lái)作為 listener 的類型

但這樣還是沒(méi)有辦法明確 listener 里邊有多少個(gè)具體的參數(shù)以及類型

// 自定義注冊(cè)事件函數(shù)的類型注釋

const addEvent = (eventType: string, listener:(...args: any[]) => any) => { ? ?console.log(eventType, listener); ? ? }addEvent('eventTypeName1', () => { })

如果是這樣,那么 調(diào)用 addEvent 時(shí)回調(diào)函數(shù)是沒(méi)有任何有用的提示的

尬住了是不是
eventType 不同,對(duì)應(yīng)的 listener 也不同
這時(shí)就應(yīng)該想是不是能用泛型來(lái)解決,泛型就是在傳入的時(shí)候才確寫(xiě)具體的類型約束

  1. 先建一個(gè)用于映射的類型對(duì)象 MyEventMap, key 是 eventType 類型, value 是對(duì)應(yīng)的 listener 類型

  2. 添加泛型 T

  3. 用 extends keyof MyEventMap 約束 T 在 MyEventMap 的 key 范圍內(nèi),而key 范圍又是通過(guò) keyof 來(lái)提取的

  4. listener 的類型通過(guò) MyEventMap[T] 來(lái)獲取

type MyEventMap = { ? ?'eventTypeName1': (a: string) => number ? ?'eventTypeName2': (test: boolean) => string[] }const addEvent = <T extends keyof MyEventMap>(eventType: T, listener: MyEventMap[T]) => { ? ?console.log(eventType, listener); }addEvent('eventTypeName1', (a) => { ? ?return 1})

這樣就有提示了,看效果

兩個(gè)關(guān)鍵點(diǎn)

  • extends 來(lái)約束 eventType

  • MyEventMap[T] 來(lái)獲取具體的 listener 類型

二、代理 DOM 事件的類型注釋

比如你自己在寫(xiě) Js 框架,其中需求是要實(shí)現(xiàn) addEventListener 的代理函數(shù),如何給這個(gè)代理函數(shù)寫(xiě)ts注釋呢?

on('click', ()=> {})?這樣的方法,且能提示 Typescript 默認(rèn)提供的類型,并約束 eventName 在dom事件

const on = (eventName: string, ?listener: (...args: any[]) => any) => { ? ?console.log(eventName, listener); }

這樣寫(xiě)也通過(guò)了檢測(cè)...那肯定不行,因?yàn)樾枨笫羌s束為 dom 事件,但現(xiàn)在約束了eventName為 string

on('click', () => { })

又尬住了,我們得在 ts 提供的 lib.dom.d.ts 文件內(nèi)找答案

源碼中找到?interface HTMLElement?的接口定義

addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;

顯然 HTMLElementEventMap 就是我們要找的通過(guò) eventName 映射 具體回調(diào)的 Map

那就和上面自定義注冊(cè)函數(shù)一樣處理就可以了即

const on = <T extends keyof HTMLElementEventMap>(eventName: T, ?listener: (this: HTMLElement, ev: HTMLElementEventMap[T]) => any, options?: boolean | AddEventListenerOptions) => { ? ?console.log(eventName, listener, options); }

這樣就都有正常的提示了

on('mousedown', (e) => { ? ?console.log(e) })

on('paste', (e) => { ? ?console.log(e) })

三、fetch 的 ts 注釋

很多情況下,我們會(huì)給 fetch 請(qǐng)求回來(lái)的函數(shù)用?data as User[]?來(lái)主動(dòng)告訴編譯器返回?cái)?shù)據(jù)的類型, 雖然能用,但不優(yōu)雅

我們會(huì)順著思路,我們?cè)囋嚱o fetch 請(qǐng)求函數(shù)作 ts 注釋

一樣先建一個(gè) ResponseMap ,key 是 三、fetch 請(qǐng)求地址 value 是 fetch 返回的數(shù)據(jù)類型

type ResponseMap = { ? ?'hello/world': number ? ?'test/getlist': string[] }const get = async <T extends keyof ResponseMap>(url: T):Promise<ResponseMap[T]> => { ? ?const response = await fetch(url); ? ?return response.json(); }

測(cè)試一下

get('hello/world')

get('test/getlist')

試了一下挺完美,但是,但是,肯定沒(méi)這么簡(jiǎn)單,請(qǐng)求地址很多情況下是帶有參數(shù)的

get('test/getlist?a=1&b=2')

發(fā)現(xiàn)提示錯(cuò)誤,通不過(guò)校驗(yàn)了

果然類型很麻煩。。。

?。。⌒枰倪M(jìn)一下泛型匹配

const get = async <T extends keyof ResponseMap>(url: T ?| `${T}?${string}`):Promise<ResponseMap[T]> => { ? ?const response = await fetch(url); ? ?return response.json(); }get('test/getlist?a=1&b=2')

這下可以通過(guò)校驗(yàn)了,提示也正常工作

關(guān)鍵在于

url: T |?${T}?${string}

這一句的改動(dòng), 通過(guò)字符串模板提取出 T 來(lái)

最后,人家的建議是泛型也需要更友好的命名,T、K、R、等等都太不友好了,可以更具名化如下, 把范圍名字變的更具體

const addEvent = <EventType extends keyof MyEventMap>(eventType: EventType, listener: MyEventMap[EventType]) => { ? ?console.log(eventType, listener); }const get = async <FetchUrl extends keyof ResponseMap>(url: FetchUrl ?| `${FetchUrl}?${string}`):Promise<ResponseMap[FetchUrl]> => { ? ?const response = await fetch(url); ? ?return response.json(); }

說(shuō)明:以上知識(shí)是看到國(guó)外某個(gè)講 typescript 的視頻中學(xué)到的,沒(méi)找到原視頻


Typescript 回調(diào)函數(shù)、事件偵聽(tīng)的類型定義與注釋的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
滕州市| 长子县| 江西省| 青阳县| 晋江市| 宁德市| 安多县| 会理县| 广州市| 乌鲁木齐县| 阿克陶县| 且末县| 阿克苏市| 高陵县| 蕲春县| 泗洪县| 云林县| 墨竹工卡县| 漠河县| 定边县| 全南县| 彭州市| 湖州市| 沾益县| 如皋市| 香格里拉县| 信阳市| 天津市| 信宜市| 霍林郭勒市| 江孜县| 浙江省| 上杭县| 安远县| 双牌县| 桃园县| 嘉峪关市| 泰和县| 永安市| 随州市| 松潘县|