日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何編寫健壯的TypeScript庫?

 當(dāng)你用 TypeScript 編寫庫時,你通常不知道這個庫最終將如何被使用。即使你 警告潛在用戶,你編寫這個庫只是針對 TypeScript 用戶,你還是可能會在某個時刻擁有 JavaScript 用戶——或者是因為他們不顧你的警告而使用這個庫,或者是他們因為傳遞性依賴而使用這個庫。這有一個非常重要的后果:你必須將這個庫設(shè)計成任何語言的開發(fā)者都可以使用!

公司主營業(yè)務(wù):網(wǎng)站建設(shè)、成都網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出東烏珠穆沁免費做網(wǎng)站回饋大家。

其主要部分是函數(shù)定義和函數(shù)體。如果你針對一個純 TypeScript 讀者編寫,那么你只需定義函數(shù)類型并信任編譯器處理其它事情。如果你針對一個純 JavaScrpit 讀者編寫,那么你需要記錄那些類型,但在函數(shù)中將實際的類型設(shè)為unknown并檢查調(diào)用方傳遞的內(nèi)容。

例如,給定如下代碼

 
 
 
  1. interface Person {
  2. age: number;
  3. name?: string;
  4. }
  5. function describe(person: Person): string {
  6. let name = person.name ?? 'someone';
  7. return `${name} is ${person.age} years old!`;
  8. }

一個 JS 用戶可能用任何東西來調(diào)用describe函數(shù)。

正確寫法:

 
 
 
  1. describe({ name: "chris" })

災(zāi)難性的錯誤寫法:?

 
 
 
  1. describe("potato");

最常見的 JS 錯誤:

 
 
 
  1. describe(undefined);

你的庫的 JS 用戶并不是故意這么做的。恰恰相反,在任何足夠大的系統(tǒng)中,很容易將錯誤的參數(shù)傳遞給系統(tǒng)中的某個函數(shù)。這通常是一個很難避免的錯誤,比如在一個點上做了修改,許多其它地方需要更新,但漏掉了一個點。故意的 JS 開發(fā)者會把壞數(shù)據(jù)發(fā)送到你設(shè)計精美的 TS API 中。

如果你針對一個純 TypeScript 讀者編寫,那么你只需定義函數(shù)類型并信任編譯器處理其它事情

我故意不提 TypeScript 編譯非常嚴(yán)格,從一個與 JavaScript 沒有區(qū)別的級別到幾乎任何人可能想到的嚴(yán)格級別。這意味著,即使是 TypeScript 調(diào)用者也應(yīng)該像 JavaScript 調(diào)用者一樣被對待:眾所周知,他們到處亂扔any,忽略了事實上可能是null或undefined的地方。返回上面的示例代碼:

 
 
 
  1. interface Person {
  2. age: number;
  3. name?: string;
  4. }
  5. function describe(person: Person): string {
  6. let name = person.name ?? 'someone';
  7. return `${name} is ${person.age} years old!`;
  8. }

在沒有啟用嚴(yán)格標(biāo)識的情況下,TypeScript 用戶可以如下調(diào)用describe:

 
 
 
  1. function cueTheSobbing(data: any) {
  2. describe(data);
  3. }
  4. cueTheSobbing({ breakfastOf: ["eggs", "waffles"] });

或者這樣:

 
 
 
  1. describe(null);

或者這樣:

 
 
 
  1. describe({ age: null })

也就是說:JS 調(diào)用者大部分會出錯的方式,TS 調(diào)用者在關(guān)閉嚴(yán)格性設(shè)置的情況下也會出錯。這意味著故意的 TypeScript 用戶也會用壞數(shù)據(jù)調(diào)用你的庫。而且由于他們依賴其它庫,這很可能不是他們的錯誤,因為這種問題可能發(fā)生在依賴圖中的任何地方。

因此,如果問題是我們不能信任數(shù)據(jù),那么我們應(yīng)該怎么做?一個選項是使函數(shù)的所有參數(shù)實際為unknown,并用 JSDoc 指定它該如何。然而,那樣會使我們失去大量 TS 提供的能力。當(dāng)與函數(shù)交互時,我們即使在內(nèi)部也不會得到補全或類型錯誤,更不用說我們的庫的用戶。但是正如我們剛剛看到的,我們也不能依賴類型定義來提供函數(shù)內(nèi)部的安全性。不過,我們可以將這幾種方法結(jié)合起來:指定類型定義,并將傳入的數(shù)據(jù)視為實際上的unknown。這確實帶來了運行時開銷——我們稍后將圍繞這個權(quán)衡進行詳細(xì)討論?,F(xiàn)在,我們可以先看看如何檢查類型。

首先,我們會像實際上會從調(diào)用者得到真正未知的數(shù)據(jù)來編寫我們的代碼,因為我們已經(jīng)確定了這正是我們可能得到的。一旦我們完成了對unknown數(shù)據(jù)的校驗,我們就能夠?qū)⑺鎿Q為Person,而且所有東西都應(yīng)該繼續(xù)工作,但是現(xiàn)在我們可以保證它對任何拋給它的數(shù)據(jù)都能夠工作。

 
 
 
  1. function describe(person: unknown): string {
  2. let name = person.name ?? 'someone';
  3. return `${name} is ${person.age} years old`;
  4. }

這里有類型錯誤,因為這里的person類型可能是undefined或"potato"或者任何其它類型。我們可以使用 TypeScript 的類型縮小的概念來保證安全。然而,從unknown縮小到特定的對象類型有點兒奇怪,因為如果你簡單地檢查是否typeof somethingUnknown === 'object',這會將類型縮小到{},這意味著它不會包含任何我們可能需要的類型。我們會先定義一個isObject輔助函數(shù),它會為我們提供正確的語義:

 
 
 
  1. function isObject(
  2. maybeObj: unknown
  3. ): maybeObj is Record {
  4. return typeof maybeObj === 'object' && maybeObj !== null;
  5. }

我們還需要一種方法來檢查這個對象有沒有指定的屬性。如果in運算符能以這種方式工作就太好了,但不幸的是,它沒有這樣工作。我們也可以內(nèi)聯(lián)這樣做,但是每次都需要類型轉(zhuǎn)換。我們可以稱之為has,類似于Object.hasOwnProperty方法。由于這還需要檢查isObject返回的類型集——在 JS 中索引一個對象的所有合法類型——我們這里會將其提取到一個新的Key類型。

這個has輔助函數(shù)的返回類型告訴類型系統(tǒng),如果主體為 true,傳入的項目有其原始類型而且它包含我們要檢查的屬性。

 
 
 
  1. type Key = string | number | symbol;
  2. function has(
  3. key: K,
  4. t: T
  5. ): t is T & Record {
  6. return key in t;
  7. }

現(xiàn)在我們可以將它們組合成一個類型保護器,來檢查給定對象是否是一個 person:

 
 
 
  1. function isPerson(value: unknown): value is Person {
  2. return (
  3. isObject(value) &&
  4. has('age', value) && typeof value.age === 'number' &&
  5. (has('name', value) ? typeof value.name === 'string' : true)
  6. )
  7. }

現(xiàn)在,我們可以將所有這些集合到我們函數(shù)頂部的一個簡單的檢查中,如果它不合法的話拋出一個有用的錯誤。

 
 
 
  1. function describe(person: unknown): string {
  2. if (!isPerson(person)) {
  3. throw new Error('`describe` requires you to pass a `Person`');
  4. }
  5. let name = person.name ?? 'someone';
  6. return `${name} is ${person.age} years old`;
  7. }

既然我們已經(jīng)有了這個功能,我們可以將這里的person類型更新為Person來讓 TypeScript 用戶有更好的體驗。

 
 
 
  1. function describe(person: Person): string {
  2. if (!isPerson(person)) {
  3. throw new Error(
  4. `'describe' takes a 'Person', but you passed ${JSON.stringify(person)}`
  5. );
  6. }
  7. let name = person.name ?? 'someone';
  8. return `${name} is ${person.age} years old`;
  9. }

TypeScript 支持在條件不包含斷言函數(shù)時拋出的這種模式泛化,這非常有用。我們可以編寫如下格式:

 
 
 
  1. function assert(
  2. predicate: unknown,
  3. message: string
  4. ): asserts predicate {
  5. if (!pred) {
  6. throw new Error(message);
  7. }
  8. }

現(xiàn)在我們的函數(shù)變得更簡單:

 
 
 
  1. function describe(person: Person): string {
  2. assert(
  3. isPerson(person),
  4. `'describe' takes a 'Person', but you passed ${JSON.stringify(person)}`
  5. );
  6. let name = person.name ?? 'someone';
  7. return `${name} is ${person.age} years old`;
  8. }

到目前為止,一直都還不錯!我們現(xiàn)在保證,無論誰調(diào)用describe,無論是從 JS,還是從松散類型的 TS,或是從其它完全不同的語言,它都會做“正確”的事情,在出錯時向調(diào)用者提供一個可操作的錯誤。然而,根據(jù)我們的限制,這種運行時校驗會開銷過大而不可行。在一個瀏覽器中,我們通過網(wǎng)絡(luò)發(fā)送的額外代碼積累起來:需要下載更多東西,也需要解析更多東西,這都會減慢我們的 app。在任何環(huán)境中,每次與describe函數(shù)交互時都會進行額外的運行時檢查。一種選項是利用一些編譯智能來在開發(fā)期間而不是在生產(chǎn)構(gòu)建中提供這些檢查。Babel 允許你將給定函數(shù)轉(zhuǎn)變成 noops,使得它們不完全沒有開銷,但開銷非常小。例如,Ember CLI 提供了一個 Babel 插件將 Ember 的assert函數(shù)(其類型與我在上面定義的assert幾乎等同)轉(zhuǎn)變成 no-ops。你可以將它與任何可以消除無用代碼的工具結(jié)合起來,以刪除所有沒有用到的輔助函數(shù)!

這種方案的缺點是,生產(chǎn)環(huán)境的錯誤的錯誤消息會比較糟糕,并且更難以調(diào)試。優(yōu)點是,在生產(chǎn)環(huán)境中,你將上傳更少的代碼且運行時開銷更少。為了使依賴這種assert片段的代碼工作,終端用戶需要將它與任何具有良好的端到端測試覆蓋的功能、UI 組件等相結(jié)合。但是不管怎樣,這都是正確的:類型和測試消除了不同類型的 bugs,最好結(jié)合使用!


網(wǎng)站標(biāo)題:如何編寫健壯的TypeScript庫?
鏈接URL:http://m.5511xx.com/article/djpogds.html