0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳解了將三萬行代碼從Flow移植到TypeScript的全過程

電子工程師 ? 來源:lq ? 2019-02-11 11:05 ? 次閱讀

在內(nèi)存安全中,類型安全是很重要的一個(gè)命題。為了確保JavaScript項(xiàng)目運(yùn)行的類型安全,本文的作者介紹了2016年時(shí)使用Flow的經(jīng)歷:由Facebook支持的Flow方案,不僅擁有查找類型、泛型參數(shù)默認(rèn)值等基本功能,還有著較為完善的JavaScript開發(fā)生態(tài)系統(tǒng)。但是隨著項(xiàng)目的不斷復(fù)雜,以及TypeScript功能的逐漸優(yōu)化,就對項(xiàng)目提出了更多的要求。本文就詳解了將三萬行代碼從Flow移植到TypeScript的全過程。

以下為譯文:

最近我們將MemSQL Studio的3萬行JavaScript代碼從Flow移植到了TypeScript。在本文中,我將介紹我們移植代碼庫的原因以及移植的全過程。

事先聲明,我寫這篇文章的目的不在于譴責(zé)Flow或Flow的使用。我非常欣賞Flow這個(gè)項(xiàng)目,我認(rèn)為在JavaScript社區(qū)中Flow和TypeScript這兩種類型檢查器都有足夠的發(fā)展空間。但是,每個(gè)團(tuán)隊(duì)都需要仔細(xì)研究并選擇最適合自己的。因此我真誠地希望這篇文章對你的選擇能有所幫助。

背景

首先介紹一下背景故事。在MemSQL,我們都喜歡靜態(tài)強(qiáng)類型的JavaScript代碼,這是為了避免動(dòng)態(tài)弱類型的常見問題。例如:

動(dòng)態(tài)弱類型問題中不同部分的代碼對于隱式類型契約的假設(shè)不一致,會(huì)引發(fā)運(yùn)行時(shí)的類型錯(cuò)誤;

而且動(dòng)態(tài)弱類型在測試小問題上花費(fèi)的時(shí)間太多,比如參數(shù)類型檢查(運(yùn)行時(shí)類型檢查也會(huì)增大打包文件的尺寸);

此外動(dòng)態(tài)弱類型還缺乏編輯器/ IDE集成,因?yàn)樵跊]有靜態(tài)類型的情況下,很難實(shí)現(xiàn)跳轉(zhuǎn)定義、自動(dòng)重構(gòu)以及其他功能;

靜態(tài)強(qiáng)類型還具有動(dòng)態(tài)弱類型問題所缺失的圍繞數(shù)據(jù)寫代碼的能力,這意味著我們可以先設(shè)計(jì)數(shù)據(jù)類型,然后我們的代碼就會(huì)“自然成型”。

這些還只是靜態(tài)類型部分的優(yōu)點(diǎn)。

2016年初,我們開始在一個(gè)內(nèi)部的JavaScript項(xiàng)目上使用tcomb,以確保運(yùn)行時(shí)的類型安全(聲明:我并沒有參與那個(gè)項(xiàng)目)。雖然有時(shí)運(yùn)行時(shí)的類型檢查很有用,但它與靜態(tài)類型毫不沾邊??紤]到這一點(diǎn),2016年的時(shí)候我們決定在另一個(gè)項(xiàng)目中使用Flow。當(dāng)時(shí),F(xiàn)low是一個(gè)很好的選擇,因?yàn)椋?/p>

Flow由Facebook支持,在日益壯大的React社區(qū)中收到了相當(dāng)多的好評(React也是用Flow開發(fā)的);

我們沒有必要嘗試一個(gè)全新的JavaScript開發(fā)生態(tài)系統(tǒng),拋棄Babel轉(zhuǎn)向tsc(TypeScript編譯器)的風(fēng)險(xiǎn)會(huì)很大,還會(huì)失去切換到Flow或其他類型檢查器的靈活性(顯然后來情況發(fā)生了變化);

我們也沒有必要在整個(gè)代碼庫上采用類型(因?yàn)槲覀兿胂葒L試一下靜態(tài)類型的JavaScript),我們只想在部分文件上采用類型(不過請注意,現(xiàn)在的Flow和TypeScript都允許開發(fā)者這么做);

當(dāng)時(shí)的TypeScript缺少Flow支持的一些基本功能,例如查找類型、泛型參數(shù)默認(rèn)值等。

當(dāng)2017年年末開始開發(fā)MemSQL Studio時(shí),我們準(zhǔn)備在整個(gè)應(yīng)用程序中實(shí)現(xiàn)完整的類型覆蓋(整個(gè)應(yīng)用程序都是用JavaScript編寫的,前端和后端都在瀏覽器中運(yùn)行)。因?yàn)橐郧俺晒κ褂玫慕?jīng)驗(yàn),所以我們決定此次也使用Flow。

然而,最新發(fā)布的Babel 7已經(jīng)開始支持TypeScript了,這引起了我的注意。這個(gè)發(fā)布意味著采用TypeScript不再需要引入整個(gè)TypeScript生態(tài)系統(tǒng),我們可以繼續(xù)通過Babel來生成JavaScript。更重要的是,這意味著實(shí)際上我們可以將TypeScript作為類型檢查器,而不是作為一種“語言”。

就個(gè)人而言,我認(rèn)為將類型檢查與JavaScript的生成分離是在JavaScript中實(shí)現(xiàn)靜態(tài)(強(qiáng))類型的更優(yōu)雅的方式,因?yàn)椋?/p>

將生成ES5和類型檢查從思想上進(jìn)行某種程度的分離是一個(gè)好主意。如此一來可以減少類型檢查鎖定的范圍,并加快開發(fā)速度(即使類型檢查因某些原因而變慢,你的代碼生成也不會(huì)受到影響)。

Babel擁有一些非常優(yōu)秀的插件和了不起的功能,這些都是TypeScript的生成器所沒有的。例如,Babel允許開發(fā)者指定想要支持的瀏覽器,它將自動(dòng)生成在這些瀏覽器上有效的代碼。不過這實(shí)現(xiàn)起來非常復(fù)雜,因此應(yīng)當(dāng)讓Babel做這一切,而不是讓社區(qū)在兩個(gè)不同項(xiàng)目上重復(fù)這種努力。

我喜歡JavaScript這種編程語言(除了它缺少靜態(tài)類型),我不知道TypeScript會(huì)最終存活多久,但我相信ECMAScript會(huì)長期存在。出于這個(gè)原因,我更喜歡用JavaScript思考和寫代碼。

注意,我一直在說“使用Flow”或“使用TypeScript”,是因?yàn)槲铱偸前阉鼈儺?dāng)成工具,而非編程語言。

當(dāng)然,這種方法也有一些缺點(diǎn):

理論上,TypeScript編譯器可以根據(jù)類型執(zhí)行優(yōu)化,但如果將生成與類型檢查分離就失去這個(gè)優(yōu)勢了;

如果需要依賴很多工具和開發(fā),那么項(xiàng)目配置會(huì)變得稍復(fù)雜。不過我認(rèn)為這個(gè)不足為慮,因?yàn)樵谖覀兊捻?xiàng)目中Babel + Flow從來都沒出現(xiàn)過配置的問題。

TypeScript 能替代Flow 方案嗎?

我注意到網(wǎng)上和本地JavaScript社區(qū)對TypeScript的興趣越來越濃厚。因此,當(dāng)發(fā)現(xiàn)Babel 7支持TypeScript時(shí),我就開始調(diào)查代替Flow的可能性。最重要的是,在使用Flow的時(shí)候我們遇到了很多挫折:

編輯器/ IDE集成的質(zhì)量很低(與TypeScript相比)。Nuclide(Facebook自己的IDE,擁有最好的Flow集成)已經(jīng)不再維護(hù),所以沒什么用了。

社區(qū)很小。各種代碼庫數(shù)量較少,且總體的類型定義質(zhì)量較低。

Facebook和社區(qū)的Flow團(tuán)隊(duì)之間缺乏公共的規(guī)劃,且互動(dòng)很少。

內(nèi)存消耗很高且內(nèi)存泄漏頻繁,我們團(tuán)隊(duì)的工程師偶爾會(huì)經(jīng)歷Flow占用10GB的RAM的現(xiàn)象。

當(dāng)然,我們還必須研究TypeScript是否合適我們。調(diào)查的過程非常復(fù)雜,但通過全面地閱讀文檔,我們發(fā)現(xiàn)Flow的每個(gè)功能在TypeScript中都有相應(yīng)的支持。之后,我又研究了TypeScript的項(xiàng)目規(guī)劃,發(fā)現(xiàn)上面提到的功能都有非常滿意的支持(例如,我們在Flow中使用的一個(gè)部分類型參數(shù)推斷的功能)。

將三萬多行代碼從 Flow 移植到 TypeScript

實(shí)際上,將所有代碼從Flow移植到TypeScript的第一步是將Babel從6升級到7。這項(xiàng)工作看似簡單,但由于我們決定將Webpack 3升級到4,所以最后花了兩天的時(shí)間。由于我們的代碼中有一些遺留的依賴,所以此次的難度要比絕大多數(shù)JavaScript項(xiàng)目都高。

完成這一步后,我們就可以用新的TypeScript預(yù)設(shè)替換Babel的Flow預(yù)設(shè),然后在用Flow編寫的完整源代碼上運(yùn)行TypeScript編譯器——結(jié)果發(fā)生了8245個(gè)語法錯(cuò)誤(只有在沒有語法錯(cuò)誤的情況下tsc的命令行工具才會(huì)報(bào)告項(xiàng)目中的真正的錯(cuò)誤)。

我們被這個(gè)數(shù)字嚇到了,但是很快我們就發(fā)現(xiàn)其中大部分是由于TypeScript不支持.js文件導(dǎo)致的。經(jīng)過一番調(diào)查,我發(fā)現(xiàn)TypeScript文件必須以“.ts”或“.tsx”結(jié)尾(包含JSX的情況)。我不想在創(chuàng)建新文件的時(shí)候猶豫是應(yīng)該使用“.ts”還是“.tsx”的擴(kuò)展名,因?yàn)檫@是一種糟糕的開發(fā)體驗(yàn)。所以,我決定將所有文件都重命名為“.tsx”(理想情況下,應(yīng)當(dāng)像Flow一樣所有的文件都具有“.js”擴(kuò)展名,但我也可以接受使用“.ts”)。

經(jīng)過這次修改后,我們有大約4000個(gè)語法錯(cuò)誤。其中大多數(shù)都與導(dǎo)入類型有關(guān),我們可以TypeScript的“import”替換,也可以使用Flow({||} vs {})中的密封對象表示法替換。在使用了幾個(gè)正則表達(dá)式替換之后,我們的語法錯(cuò)誤數(shù)量降到了414個(gè)。剩下的部分只能手動(dòng)修復(fù)了:

部分泛型類型參數(shù)推斷中使用的既存型別必須替換為顯式命名的各種類型的參數(shù),或通過unknown類型告訴TypeScript我們并不關(guān)心某些類型的參數(shù);

$Keys類型和其他Flow高級類型在TypeScript中具有不同的語法,例如,$Shape <>與TypeScript中的Partial<>對應(yīng))。

修復(fù)了所有語法錯(cuò)誤之后,tsc(TypeScript編譯器)終于告訴我們,代碼庫中大約有1300個(gè)真正的類型錯(cuò)誤。這時(shí)我們不得不坐下商量是否還應(yīng)該繼續(xù),畢竟,如果要花費(fèi)數(shù)周的開發(fā)時(shí)間,此次移植就得不償失了。但是,我們發(fā)現(xiàn)只需花費(fèi)不到1周的時(shí)間就可以完成移植,所以我們決定繼續(xù)。

注意,在轉(zhuǎn)換期間,我們必須停止代碼庫的開發(fā)工作。當(dāng)然,在移植期間依然可以繼續(xù)開發(fā)新代碼,但是你必須在可能有數(shù)百種之多的類型錯(cuò)誤上進(jìn)行工作,這不是一件易事。

都有哪些類型錯(cuò)誤?

在很多方面,TypeScript和Flow都做出了不同的假設(shè),在實(shí)踐中這意味著JavaScript代碼的行為會(huì)有所不同。在某些方面Flow更嚴(yán)格,而TypeScript在其他方面又更為嚴(yán)格。深入比較兩種類型檢查會(huì)花費(fèi)大量時(shí)間,所以在本文中我只舉幾個(gè)例子。

注意:本文中所有的TypeScript練習(xí)環(huán)境(http://www.typescriptlang.org/play/)的鏈接都假設(shè)所有的“嚴(yán)格”設(shè)置都被打開了,但遺憾的是在分享TypeScript練習(xí)環(huán)境時(shí),這些設(shè)置都不會(huì)保存到URL中。因此,可以點(diǎn)擊上面的連接打開TypeScript練習(xí)環(huán)境之后再手動(dòng)設(shè)置。

invariant.js

我們的源代碼中有一個(gè)很常用的函數(shù)invariant,這個(gè)文檔(https://github.com/zertosh/invariant#invariantcondition-message)很好地解釋了它的功能:

varinvariant=require('invariant');invariant(someTruthyVal,'Thiswillnotthrow');//Noerrorsinvariant(someFalseyVal,'Thiswillthrowanerrorwiththismessage');//Errorraised:InvariantViolation:Thiswillthrowanerrorwiththismessage

這是個(gè)非常簡單的函數(shù),它能在某些條件下拋出異常。下面讓我們來看看在Flow中它的實(shí)現(xiàn)與使用:

typeMaybe=T|void;functioninvariant(condition:boolean,message:string){if(!condition){thrownewError(message);}}functionf(x:Maybe,c:number){if(c>0){invariant(x!==undefined,"Whencispositive,xshouldneverbeundefined");(x+1);//worksbecausexhasbeenrefinedto"number"}}

下面,我們通過TypeScript運(yùn)行完全相同的代碼片段。正如在鏈接中看到的那樣,TypeScript出錯(cuò)了,因?yàn)樗磺宄詈笠恍惺欠窨梢源_?!皒”不會(huì)被定義為undefined。這是一個(gè)眾所皆知的TypeScript的問題——它無法在函數(shù)中進(jìn)行這類的推理。但是,由于這樣的代碼在我們代碼庫中很常見,所以我們就被迫手動(dòng)替換每一個(gè)invariant的實(shí)例(有150多個(gè)):

typeMaybe=T|void;functionf(x:Maybe,c:number){if(c>0){if(x===undefined){thrownewError("Whencispositive,xshouldneverbeundefined");}(x+1);//worksbecausexhasbeenrefinedto"number"}}

雖然這不如invariant那么好,但也不算大問題。

$ ExpectError vs @ ts-ignore

Flow有一個(gè)非常有趣的功能,類似于@ ts-ignore,不過不同的是如果下一行不是錯(cuò)誤,那么它就會(huì)出錯(cuò)。在編寫“類型測試”時(shí),這個(gè)功能很有用。類型測試可以確保類型檢查(無論是TypeScript還是Flow)按照我們的期望找到某些類型錯(cuò)誤。

不幸的是,TypeScript沒有這個(gè)功能,這意味著我們的類型測試失去了部分價(jià)值——這也是我期待TypeScript能夠?qū)崿F(xiàn)的功能。

一般的類型錯(cuò)誤和類型推斷

通常,TypeScript會(huì)比Flow更清晰,如下例所示:

typeLeaf={host:string;port:number;type:"LEAF";};typeAggregator={host:string;port:number;type:"AGGREGATOR";}typeMemsqlNode=Leaf|Aggregator;functionf(leaves:Array,aggregators:Array):Array{//Thenextlineerrorsbecauseyoucannotconcataggregatorstoleaves.returnleaves.concat(aggregators);}

Flow推斷l(xiāng)eaves.concat(aggregators) 的類型為Array ,然后將其轉(zhuǎn)換為Array。我認(rèn)為這是一個(gè)很好的例子,說明有的地方Flow很聰明,而TypeScript可能需要一點(diǎn)幫助(在這種情況下,我們可以用類型斷言來幫助TypeScript,但是類型斷言的使用很危險(xiǎn),請小心謹(jǐn)慎)。

盡管沒有正式的證據(jù),但是我還是想說我認(rèn)為在類型推斷方面Flow比TypeScript更優(yōu)越。我非常希望TypeScript能夠向Flow看齊, 因?yàn)門ypeScript正處于非常積極的開發(fā)中,并且最近TypeScript有了許多改進(jìn)。而縱觀我們的源代碼,我們必須通過解釋或類型斷言給予TypeScript一些幫助(還是盡可能地避免使用類型斷言)。讓我們再來看一個(gè)例子(我們有200多個(gè)這種類型錯(cuò)誤的實(shí)例):

typePlayer={name:string;age:number;position:"STRIKER"|"GOALKEEPER",};typeF=()=>Promise>;constf1:F=()=>{returnPromise.all([{name:"DavidGomes",age:23,position:"GOALKEEPER",},{name:"CristianoRonaldo",age:33,position:"STRIKER",}]);};

在TypeScript你不能這樣寫,因?yàn)樗辉试S你將{ name: "David Gomes", age: 23, type: "GOALKEEPER" }當(dāng)作Player類型的對象(打開練習(xí)環(huán)境可以看到確切的錯(cuò)誤)。這是另一個(gè)我覺得TypeScript“不夠聰明”的地方——至少與Flow相比不夠聰明。

為了修正這個(gè)錯(cuò)誤,開發(fā)者有幾個(gè)選擇:

斷言"STRIKER"為"STRIKER",這樣TypeScript就可以理解該字符串是個(gè)有效的枚舉類型"STRIKER" | "GOALKEEPER";

斷言整個(gè)對象為“Player”(as Player);

或者(我認(rèn)為的最佳解決方案)無需任何類型的斷言,只需寫Promise.all(...)。

另一個(gè)TypeScript的例子如下所示,這段代碼再次表明Flow具有更好的類型推斷:

typeConnection={id:number};declarefunctiongetConnection():Connection;functionresolveConnection(){returnnewPromise(resolve=>{returnresolve(getConnection());})}resolveConnection().then(conn=>{//TypeScripterrorsinthenextlinebecauseitdoesnotunderstand//thatconnisoftypeConnection.Wehavetomanuallyannotate//resolveConnectionasPromise.(conn.id);});

一個(gè)很小但非常有趣的例子是Flow判斷Array.pop()的類型為T,而TypeScript則認(rèn)為它屬于T | void。這是我喜歡TypeScript的一個(gè)地方,因?yàn)樗鼤?huì)強(qiáng)制你仔細(xì)檢查該項(xiàng)是否存在(如果數(shù)組為空,則Array.pop返回undefined)。

TypeScript對于第三方依賴的定義

當(dāng)然,在編寫任何JavaScript應(yīng)用程序時(shí)都有可能會(huì)有一些依賴。這些依賴都需要類型定義,否則開發(fā)者就失去了靜態(tài)類型分析的大部分威力(如本文開頭所述)。

從npm導(dǎo)入的庫可以附帶Flow類型定義或TypeScript類型定義,也可以兩者兼有或兩者都沒有。許多小型庫不帶有任何方式的類型,所以必須自己編寫類型定義,或從社區(qū)中找。Flow和TypeScript社區(qū)都有一個(gè)標(biāo)準(zhǔn)的JavaScript包的第三方類型定義代碼倉庫:flow-typed和DefinitelyTyped。

我不得不說使用DefinitelyTyped的體驗(yàn)更好。在使用flow-typed的時(shí)候,我們必須通過它的命令行工具將各種依賴的類型定義引入到項(xiàng)目中。DefinitelyTyped找到了一個(gè)很好的方法與npm的命令行集成,即它的軟件包均以@types/package-name的方式命名。這一點(diǎn)非常了不起,有了它我們就可以很容易地為依賴引入類型定義了(jest、react、lodash、react-redux等等)。

除此之外,我花了大量時(shí)間向DefinitelyTyped貢獻(xiàn)代碼(當(dāng)將代碼從Flow移植到TypeScript時(shí),不要指望類型定義是等價(jià)的)。我已經(jīng)發(fā)送了幾個(gè)拉取請求,所有工作都易如反掌。開發(fā)者只需要克隆、編輯類型定義、添加測試,然后發(fā)送拉取請求,DefinitelyTyped GitHub會(huì)將曾向這個(gè)類型定義貢獻(xiàn)過代碼的人標(biāo)記為審核者。如果7日之內(nèi)沒有人審核代碼,那么DefinitelyTyped的維護(hù)者會(huì)審核PR。在合并到master分支后,新版本的依賴包將會(huì)發(fā)送到npm。例如,當(dāng)我第一次更新@types/redux-form包時(shí),在合并到master分支后版本7.4.14自動(dòng)被推送到了npm。我們可以非常容易地更新package.json文件,就可以獲取新的類型定義。如果等不到PR被接受,那么也可以隨時(shí)覆蓋項(xiàng)目中使用的類型定義。

總的來說,DefinitelyTyped中類型定義的質(zhì)量更好,這要?dú)w功于TypeScript背后的社區(qū)更大、更繁榮。事實(shí)上,在將我們的項(xiàng)目從Flow移植到TypeScript之后,我們的類型覆蓋率從88%提高到了96%,主要是由于更好的第三方依賴類型定義,“any”類型的依賴減少了。

Linting與測試

在移植過程中,我們發(fā)現(xiàn)使用TypeScript的eslint比較復(fù)雜,所以我們就選擇了tslint,從eslint轉(zhuǎn)移到了tslint。

此外,我們還使用ts-jest來運(yùn)行TypeScript的測試。有些測試是有類型的,而有些是無類型的(如果給測試用例添加類型的工作量太大,我們就將它們保存成.js文件)。

修復(fù)了所有類型錯(cuò)誤后,情況怎樣了?

經(jīng)過歷時(shí)一周的修復(fù)工作后,我們遇到了最后一個(gè)類型錯(cuò)誤,我們決定利用@ts-ignore將其暫且擱置。

在解決了一些代碼審查注釋并修復(fù)了一些錯(cuò)誤之后(不幸的是,我們不得不修改少量運(yùn)行時(shí)來修復(fù)TypeScript無法理解的邏輯),在這個(gè)PR被合并后,我們就開始使用TypeScript了。(還有,我們在后續(xù)的PR中修復(fù)了最后一個(gè)@ts-ignore)。

除了編輯器集成之外,TypeScript的使用體驗(yàn)與Flow非常相似。Flow服務(wù)器的性能稍微快一點(diǎn),但這并不是一個(gè)大問題,因?yàn)樵跒槟阏诓榭吹奈募峁﹥?nèi)聯(lián)錯(cuò)誤時(shí)它們一樣快。唯一的性能差異在于TypeScript需要更長的時(shí)間(約0.5到1秒)才能告訴你在保存某個(gè)文件后,項(xiàng)目中是否有新的錯(cuò)誤。服務(wù)器啟動(dòng)時(shí)間大約相同(約2分鐘),但這并不重要。到目前為止,我們還沒遇到過內(nèi)存消耗的問題,tsc使用的內(nèi)存一直穩(wěn)定在大約600Mb。

可能看起來Flow的類型推斷比TypeScript更好,但是兩個(gè)原因可以解釋為什么這不是什么大問題:

我們將代碼庫從Flow移植到了TypeScript,這意味著我們在其中發(fā)現(xiàn)了Flow可以表達(dá)但TypeScript卻不能表達(dá)的地方。如果這次移植是從TypeScript到Flow的,那么我們可能就會(huì)發(fā)現(xiàn)TypeScript的推斷/表達(dá)比Flow更好。

類型推斷很重要,它有助于保持我們的代碼更簡潔。但是強(qiáng)大的社區(qū)、類型定義的可用性等更為重要,因?yàn)槿躅愋屯茢嘀恍枰訌?qiáng)下類型檢查就可以解決。

代碼統(tǒng)計(jì)

$npmruntype-coverage#https://github.com/plantain-00/type-coverage43330/4504796.19%

$cloc#ignoringtestsanddependencies--------------------------------------------------------------------------------Languagefilesblankcommentcode--------------------------------------------------------------------------------TypeScript3305179140531463

下一步計(jì)劃?

雖然移植完成了,但是代碼中的靜態(tài)類型分析還沒有完成。

MemSQL還有其他項(xiàng)目也打算棄用Flow、轉(zhuǎn)而投入TypeScript的懷抱(有些JavaScript項(xiàng)目可能一開始就使用TypeScript),所以我們希望使我們的TypeScript配置更加嚴(yán)格。

目前我們已經(jīng)打開了“strictNullChecks”,但“noImplicitAny”仍處于禁用狀態(tài),這也需要后續(xù)解決。

此外,我們還打算刪除代碼中的一些危險(xiǎn)的類型斷言。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4788

    瀏覽量

    68616
  • 編輯器
    +關(guān)注

    關(guān)注

    1

    文章

    806

    瀏覽量

    31173
  • Flow
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    8845

原文標(biāo)題:如何將三萬行代碼從Flow移植到TypeScript?

文章出處:【微信號:rgznai100,微信公眾號:rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    電流鏡設(shè)計(jì)步驟詳解全過程

    設(shè)計(jì)。電流鏡設(shè)計(jì)步驟詳解全過程】[/hide]大致內(nèi)容為: 1、邊界條件2、設(shè)計(jì)指標(biāo) 3、確定電路拓?fù)浣Y(jié)構(gòu)4、設(shè)計(jì)變量初始估算5、HSPICE仿真驗(yàn)證6、版圖設(shè)計(jì)7、討論&結(jié)論
    發(fā)表于 11-04 16:31

    PCB 制作全過程

    `PCB 制作全過程。`
    發(fā)表于 08-05 22:43

    圖文詳解2000元電動(dòng)汽車DIY全過程

    `圖文詳解2000元電動(dòng)汽車DIY全過程`
    發(fā)表于 08-15 19:05

    音箱制作全過程

    音箱制作全過程
    發(fā)表于 08-16 17:00

    有人分享制作藍(lán)牙耳機(jī)的全過程嗎?

    我想自己制作一個(gè)藍(lán)牙耳機(jī),但是技術(shù)不夠,希望有人分享下藍(lán)牙耳機(jī)的制作全過程,可以是模塊應(yīng)用,最好是底層開始制作的,包括軟件的編寫代碼。{:23:}
    發(fā)表于 06-02 18:42

    cadence原理圖PCB設(shè)計(jì)全過程(精華)

    cadence原理圖PCB設(shè)計(jì)全過程
    發(fā)表于 10-24 14:06

    記錄STM32f407程序移植GD32F407的全過程

    0、前言本文記錄STM32f407程序移植GD32F407的全過程,兩個(gè)芯片是pin to pin,基本特性都是,最大168MHZ,1024k flash,192K sram,LQFP100封裝
    發(fā)表于 01-26 08:17

    CPU制造全過程

    CPU制造全過程第1頁:由沙晶圓,CPU誕生全過程     沙中含有25%的硅,是地殼中第二多元素,在經(jīng)過氧化之后就成為了二氧化硅,在沙,尤其是石英中二氧
    發(fā)表于 09-22 08:08 ?77次下載

    淺論建筑工程全過程造價(jià)控制

    建筑工程全過程造價(jià)是相對于建筑工程階段造價(jià)控制而言的。指項(xiàng)目立項(xiàng)至竣工交付使用全過程的造價(jià)確定、控制。起具體包括以下工作:立項(xiàng)的必要性研究,可行性研究及報(bào)告
    發(fā)表于 12-28 15:46 ?12次下載

    組裝電腦全過程視頻教程

    組裝電腦全過程視頻教程 教你認(rèn)識電腦主機(jī)各種配件及組裝接線方法
    發(fā)表于 09-14 11:05 ?467次下載

    IGBT制作全過程資料下載

    電子發(fā)燒友網(wǎng)為你提供IGBT制作全過程資料下載的電子資料下載,更有其他相關(guān)的電路圖、源代碼、課件教程、中文資料、英文資料、參考設(shè)計(jì)、用戶指南、解決方案等資料,希望可以幫助廣大的電子工程師們。
    發(fā)表于 04-15 08:49 ?25次下載
    IGBT制作<b class='flag-5'>全過程</b>資料下載

    用C語言開發(fā)DSP系統(tǒng)的全過程的講解

    用C語言開發(fā)DSP系統(tǒng)的全過程的講解。
    發(fā)表于 05-26 14:17 ?22次下載

    手工制作pcb全過程

    手工制作pcb全過程介紹。
    發(fā)表于 06-19 10:18 ?0次下載

    芯片制造全過程

    有人說芯片是人類最高智慧的代表,很多人都無法理解,接下來跟隨小編一起了解芯片的制作全過程,看完你就懂了。
    的頭像 發(fā)表于 12-08 17:42 ?1.2w次閱讀

    電磁爐的維修全過程分享

    電磁爐的維修全過程分享
    發(fā)表于 01-10 15:16 ?84次下載