CesiumJS新增官方TypeScript類(lèi)型定義

Cesium中文網(wǎng):http://cesiumcn.org/ | 國(guó)內(nèi)快速訪問(wèn):http://cesium.coinidea.com/

在當(dāng)前的1.70版本中,CesiumJS現(xiàn)在附帶了正式的TypeScript類(lèi)型定義!

TypeScript定義是一個(gè)長(zhǎng)期以來(lái)被要求的特性。雖然社區(qū)已經(jīng)完成了一項(xiàng)支持各種手動(dòng)方式的工作,其中最受歡迎的是@types/cesium,但是cesium代碼庫(kù)的龐大規(guī)模和不斷發(fā)展的特性使得手工維護(hù)成為一項(xiàng)永無(wú)止境的任務(wù)。官方定義文件Cesium.d.ts的數(shù)據(jù)量超過(guò)42000行,達(dá)1.9MB。

即使您不是TypeScript用戶,此工作的性質(zhì)也提高了CesiumJS API參考文檔的正確性和完整性,并在IDE中實(shí)現(xiàn)了更好的intellisense支持,可以將TypeScript定義應(yīng)用于推斷類(lèi)型,從而使整個(gè)CesiumJS社區(qū)獲得了巨大的成功。

更新CesiumJS到1.70將自動(dòng)利用TypeScript應(yīng)用程序中的類(lèi)型檢查。我們使用package.json中的types字段,在大多數(shù)情況下不需要額外的配置。但是,如果直接導(dǎo)入單個(gè)Cesium源文件,則需要將“types”:[“cesium”]添加到tsconfig.json配置以便獲取定義。如果您以前使用過(guò)@types/cesium,則可以將其移除。

來(lái)自CesiumJS團(tuán)隊(duì)的官方支持意味著最新和正確的定義文件將隨每個(gè)版本一起發(fā)布。這也意味著TypeScript支持將作為CesiumJS GitHub存儲(chǔ)庫(kù)的一部分進(jìn)行正式跟蹤。如果您在使用帶有TypeScript的CesiumJS時(shí)發(fā)現(xiàn)一個(gè)bug,請(qǐng)打開(kāi)一個(gè)問(wèn)題(issue)或更好的方法,一個(gè)pull request請(qǐng)求來(lái)解決它。如果您對(duì)CesiumJS/TypeScript有疑問(wèn),或者需要幫助調(diào)試您的項(xiàng)目,請(qǐng)?jiān)谏鐓^(qū)論壇(community forum)上提問(wèn)。

如果您正在使用自定義的或@types/cesium,但尚未準(zhǔn)備好切換,則可以在安裝后刪除Source/cesium.d.ts。然后,TypeScript工具將返回到它找到的下一組CesiumJS類(lèi)型定義。

image.png

官方的類(lèi)型定義文件,Cesium.d.ts記錄了超過(guò)42000行的聲明和文檔,其大小達(dá)1.9MB。

深入了解

雖然我們很高興終于正式支持TypeScript,但要做到這一點(diǎn)還需要一些努力。最初,我們探討了3種選擇:

手動(dòng)維護(hù)定義文件

我們可以手動(dòng)管理和維護(hù)自己的TypeScript定義文件,作為CesiumJS代碼庫(kù)的一部分,很可能是每個(gè)JavaScript文件都有一個(gè)單獨(dú)的定義文件,使其易于管理,比如Cartesian3.js對(duì)應(yīng)Cartesian3.d.ts。在技術(shù)層面這樣易于實(shí)現(xiàn),但對(duì)文件同步和維護(hù)性上來(lái)說(shuō),會(huì)造成較大傷害。

另外,我們不想只包含聲明接口,也不想包含內(nèi)聯(lián)文檔,這樣用戶就可以充分利用intellisense。這是我們最后的選擇,但如果結(jié)果證明這是唯一可行的選擇,那就是我們最終的選擇。

移植CesiumJS到TypeScript

您可能會(huì)驚訝地聽(tīng)說(shuō)我們實(shí)際上評(píng)估過(guò)用TypeScript重寫(xiě)所有CesiumJS。對(duì)于TypeScript開(kāi)發(fā)人員來(lái)說(shuō),這將是一個(gè)巨大的改進(jìn),對(duì)于CesiumJS維護(hù)人員和代碼庫(kù)來(lái)說(shuō),這也是一個(gè)真正的勝利。除了強(qiáng)類(lèi)型檢查之外,它還將使我們快速使用現(xiàn)代約定,如template literals、arrow functions和async/await,由于兼容性和工具的原因,我們目前不允許在CesiumJS代碼庫(kù)中使用這些約定。

不幸的是,所需的努力程度和所工作量使它在短期內(nèi)不會(huì)成為一個(gè)有吸引力的選擇。這個(gè)選項(xiàng)仍然擺在桌面上,但正如我們?nèi)ツ晁龅拇笠?guī)模ES6遷移一樣,它需要大量仔細(xì)的規(guī)劃、研究和基礎(chǔ)設(shè)施工作才能正常進(jìn)行。

使用TypeScript編譯器生成定義文件

從TypeScript 3.7開(kāi)始,編譯器可以編譯帶有JSDoc注釋的JavaScript代碼,并為我們生成對(duì)應(yīng)的類(lèi)型定義文件。這種方法完全不需要手動(dòng)維護(hù).d.ts文件,而且還具有驗(yàn)證和改進(jìn)我們自己的JSDoc注釋的額外好處,因?yàn)樗鼈冃枰獪?zhǔn)確才能生成正確的類(lèi)型定義。不用說(shuō),這個(gè)選項(xiàng)對(duì)我們非常有吸引力,我們決定在一些初步的原型設(shè)計(jì)實(shí)驗(yàn)表明它可以工作后運(yùn)行它。

實(shí)際上,我們花了幾個(gè)星期的時(shí)間來(lái)研究這種方法Marco Hutter參與了大量的文檔修復(fù)和源代碼調(diào)整工作,以使編譯器滿意。早期的工作很有希望。正如預(yù)期的那樣,它暴露了JSDoc注釋中的錯(cuò)誤和不一致,并在較小程度上暴露了我們修復(fù)的CesiumJS API。不幸的是,我們很快就碰壁了。

依賴TypeScript編譯器意味著當(dāng)它做了一些錯(cuò)誤或意外的事情時(shí),我們?nèi)狈x擇。雖然編譯器在某些情況下使用JSDoc注釋,但在許多情況下,它依賴于自己的類(lèi)型推斷,并且沒(méi)有為我們提供重寫(xiě)它的方法。它還完全忽略了大部分JSDoc,比如在對(duì)象定義屬性,并將所有私有下劃線變量作為定義的一部分公開(kāi)。這導(dǎo)致我們開(kāi)始以我們不習(xí)慣的方式彎曲CesiumJS基礎(chǔ)代碼,只是為了讓TypeScript編譯器滿意。我們提出了嘗試修改TypeScript編譯器本身的想法,但是我們必須深入研究編譯器代碼,我們甚至不確定維護(hù)人員會(huì)接受什么,也不知道這個(gè)過(guò)程需要多長(zhǎng)時(shí)間。最終,我們最喜歡的解決方案變成了一場(chǎng)曠日持久的賭博,我們對(duì)這種方法失去了信心。

左圖:UrlTemplateImageryProvider的JSDoc, 意外地添加了屬性到BingMapsImageryProvider;右圖:生成的BingMapsImageryProvider定義,包含了重復(fù)定義,導(dǎo)致編譯失敗。

繪圖板

結(jié)果,我們對(duì)TypeScript擁有官方JSDoc支持非常興奮,以至于完全忽略了類(lèi)似的選項(xiàng) tsd-jsdoc。tsd jsdoc是jsdoc的插件,它從jsdoc輸出生成類(lèi)型腳本定義。這使得它非常類(lèi)似于TypeScript編譯器方法,但提供了對(duì)生成的類(lèi)型定義有了更大的自由度。

tsd-jsdoc不直接解析JavaScript,而是依賴于jsdoc生成的抽象語(yǔ)法樹(shù)(AST)。這意味著它不受類(lèi)型推斷問(wèn)題或缺乏JSDoc完整性的影響,這使得TypeScript編譯器接近失敗。如果我們可以使用JSDoc注釋來(lái)表示類(lèi)型,那么它就是我們希望它出現(xiàn)在類(lèi)型定義文件中的類(lèi)型。

我們已經(jīng)從以前的TypeScript編譯器方法的失敗中學(xué)到了很多,所以我們能夠相當(dāng)快地完成一個(gè)可行性評(píng)估,并且我們現(xiàn)有的JSDoc不正確的所有問(wèn)題仍然適用。事情的進(jìn)展比我們想象的要快,我們知道我們找到了解決辦法。

作為開(kāi)發(fā)人員,有時(shí)我們過(guò)于專注于某項(xiàng)技術(shù),以至于忽略了其他選擇。在這種情況下,社區(qū)成員 @bampakoa去年甚至向CesiumJS和tsd-jsdoc提交了pull請(qǐng)求,以使它們更加兼容。我們已經(jīng)知道tsd jsdoc存在,但是我們?cè)谧畛醯脑u(píng)估中忽略了它,因?yàn)槲覀兗俣薚ypeScript編譯器選項(xiàng)會(huì)更好,并且我們意外地選擇性地忽視了tsd-jsdoc。

Post-processing和驗(yàn)證

雖然tsd-jsdoc輸出是相當(dāng)高質(zhì)量的開(kāi)箱即用,但是我們做了一些額外的后處理來(lái)進(jìn)一步改進(jìn)它。這包括簡(jiǎn)單的字符串操作、正則表達(dá)式查找和替換,甚至使用TypeScript編譯器重寫(xiě)部分文件。所有這些都是作為新構(gòu)建ts gulp任務(wù)的一部分發(fā)生的。如果你好奇,可以獲得這些代碼check out the code.。最終的結(jié)果是一個(gè)單獨(dú)的Cesium.d.ts,與生成的Cesium.js模塊的入口點(diǎn)。

除了生成輸出,build-ts任務(wù)還通過(guò)使用TypeScript編譯文件來(lái)驗(yàn)證文件。如果開(kāi)發(fā)人員在JSDoc中犯了錯(cuò)誤,比如拼錯(cuò)類(lèi)名或引用私有或不存在的類(lèi)型,那么構(gòu)建過(guò)程將失敗。雖然這個(gè)驗(yàn)證過(guò)程非常有用,但它只捕獲某些類(lèi)型的錯(cuò)誤。例如,如果有人實(shí)現(xiàn)了一個(gè)新的ImageryProvider,但不符合正確的接口,則定義文件將編譯而不出錯(cuò),但TypeScript將在嘗試將新類(lèi)用作ImageryProvider的應(yīng)用程序中發(fā)出編譯錯(cuò)誤。

我們?nèi)栽谔剿魈砑宇~外驗(yàn)證的想法,例如用TypeScript編寫(xiě)一些單元測(cè)試,以識(shí)別開(kāi)發(fā)過(guò)程中潛在的問(wèn)題區(qū)域。

JSDoc錯(cuò)誤

我已經(jīng)多次提到,基于JSDoc的方法的一個(gè)特別令人興奮的地方是,它為我們的文檔添加了另一個(gè)級(jí)別的檢驗(yàn)和驗(yàn)證,使每個(gè)人都受益,而不僅僅是TypeScript開(kāi)發(fā)人員。我們的文檔審查過(guò)程的一大部分現(xiàn)在已經(jīng)自動(dòng)化了。我們?cè)诖a庫(kù)中發(fā)現(xiàn)的問(wèn)題可以分為以下幾類(lèi):

  • 不正確或不完整的類(lèi)型- 在許多情況下,我們對(duì)類(lèi)型使用了非正式或不正確的名稱,例如,Image實(shí)際上是HTMLImageElement,Canvas是htmlCanvaseElement。一個(gè)有趣的例子是TypedArray,它甚至不存在于規(guī)范級(jí)別,而是完整類(lèi)型列表的通用術(shù)語(yǔ),例如Int8Array、Float32Array等等……我們還有不完整的泛型,例如Promise而不是Promise<boolean style="box-sizing: border-box;">。</boolean>
  • @exports – 我們使用JSDoc的@exports標(biāo)簽作為最終的支撐。如果開(kāi)發(fā)人員無(wú)法在生成的HTML中顯示某些內(nèi)容,他們可能會(huì)添加@exports,這將“正常工作”。我們將@exports用于枚舉、命名空間和函數(shù),而不是@enum、@namespace和@function標(biāo)記。這導(dǎo)致了不正確的類(lèi)型生成。實(shí)踐證明我們根本不需要在代碼中的任何地方使用@exports。
  • 私有類(lèi)型泄露 – 公共API中引用了很多私有類(lèi)型。這些私有類(lèi)型不存在于HTML輸出中,對(duì)于我們的文檔構(gòu)建步驟來(lái)說(shuō)只是無(wú)聲的失敗。在大多數(shù)情況下,只公開(kāi)私有類(lèi)型是有意義的。謝天謝地,我們也有在CesiumJS中記錄私有類(lèi)型的習(xí)慣,因此不必編寫(xiě)新的JSDoc。
  • 復(fù)制粘貼錯(cuò)誤 – 最后一種JSDoc錯(cuò)誤是與復(fù)制和粘貼相關(guān)的重復(fù)參數(shù)條目,例如,讓ImageryProvider A,聲明它正在記錄ImageryProvider B上的屬性,等等…

下一步

一旦社區(qū)開(kāi)始使用這些定義,我們希望在接下來(lái)的幾個(gè)CesiumJS版本中會(huì)出現(xiàn)一些小問(wèn)題。我們還開(kāi)始開(kāi)發(fā)一個(gè)我們想要探索的想法列表,比如為實(shí)體API使用的屬性接口利用泛型。最終,我們依靠社區(qū)告訴我們對(duì)開(kāi)發(fā)者最重要的是什么,這樣我們就可以用TypeScript路線圖來(lái)塑造我們的CesiumJS 。

我們還想找出一種在CesiumJS基礎(chǔ)代碼中使用TypeScript定義的方法。我們相信VSCode有一些機(jī)制可以實(shí)現(xiàn)這一點(diǎn),但是我們還沒(méi)有探索它們。如果這被證明是可行的,那么這將是一個(gè)重大的勝利,并允許通過(guò)普通JavaScript進(jìn)行另一個(gè)級(jí)別的驗(yàn)證,更不用說(shuō)讓開(kāi)發(fā)CesiumJS成為比現(xiàn)在更好的體驗(yàn)了。

我敢肯定,當(dāng)我說(shuō)我們?cè)u(píng)估用TypeScript重寫(xiě)CesiumJS時(shí),很多人都振作起來(lái)了。我絕對(duì)贊成延長(zhǎng)時(shí)間。作為評(píng)估過(guò)程的一部分,我實(shí)際使用TypeScript編譯器構(gòu)建了現(xiàn)有的JavaScript代碼庫(kù),甚至將一些基本文件(如Cartesian3.js)移植到TypeScript,以了解如何進(jìn)行TS/js混合開(kāi)發(fā),而不是“一次完成”遷移策略。很像ES6,移植代碼是最簡(jiǎn)單的部分。預(yù)計(jì)很快就會(huì)出現(xiàn)GitHub issue,它將打破所有必須發(fā)生的事情,使CesiumJS的TypeScript版本成為現(xiàn)實(shí);但目前還沒(méi)有承諾。

致謝

我只想再次感謝社區(qū)在過(guò)去幾年中幫助產(chǎn)生了關(guān)于TypeScript的想法和討論,特別向@thw0rted致謝,他是第一個(gè)改進(jìn)初始TypeScript類(lèi)型定義的外部貢獻(xiàn)者,在最初的pull request中提供了很多很好的反饋。最后,非常感謝我的伙伴和維護(hù)人員 Kevin Ring,他不僅提供了大量的專家知識(shí)和反饋,還讓自己投入到這項(xiàng)工作中,并最終對(duì)代碼進(jìn)行了一系列改進(jìn)。

作者:Matthew Amato

原文鏈接:https://cesium.com/blog/2020/06/01/cesiumjs-tsd/

評(píng)語(yǔ):TypeScript的引入,使得CesiumJS成為更加專業(yè)的庫(kù),同時(shí)使其更易于維護(hù)。當(dāng)然移植是一個(gè)痛苦的過(guò)程。

Cesium中文網(wǎng)交流QQ群:807482793

Cesium中文網(wǎng):http://cesiumcn.org/ | 國(guó)內(nèi)快速訪問(wèn):http://cesium.coinidea.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,290評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,776評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,510評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,866評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,036評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,331評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,536評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,754評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,154評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,469評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,273評(píng)論 3 399
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,505評(píng)論 2 379