circumspect
是一組讓您的 TypeScript/JavaScript 程式碼更安全的函數。這些函數包括invariant
、 warning
、 assertNever
等。
有許多有用的函數可以讓您的程式碼更安全,例如invariant
和assertNever
。其中許多函數都可以作為單獨的 npm 套件提供(例如invariant
)。但是為每個函數安裝一個新的套件(大多數時候還有@types
對應的套件)並不是很方便。此外,這些套件通常將其函數匯出為預設匯出,使得 VSCode 自動匯入無法與它們很好地配合。
該庫將使您的程式碼更安全的功能統一到一個地方。 circumspect
是一個擁有所有這些的單一依賴。 VSCode 會自動匯入按預期工作,因為由circumspect
提供的所有功能都被命名為匯出。
此外, circumspect
是 100% 用 TypeScript 編寫的,因此預設情況下每個函數都是正確鍵入的。因此,無需安裝單獨的@types
套件。
使用紗線:
yarn add circumspect
使用 npm:
npm install circumspect
invariant
warning
assertNever
nonNull
invariant
invariant ( value : unknown , message ?: string ) : asserts value
value: unknown
是我們要確保真實的值。
message?: string
是一個可選的錯誤訊息,當傳遞的value
假時,該訊息將包含在引發的錯誤中。此自訂錯誤訊息僅在開發中顯示。在生產中,會顯示一般錯誤( 'Invariant violation'
),且message
參數將被忽略。
asserts value
意味著該函數只是將value
的類型縮小為真值並且不傳回任何內容。 invariant
確保指定的value
是真實的。如果不是這種情況,它會拋出包含指定message
錯誤(僅在開發中)。此函數透過排除所有虛假值(例如null
和undefined
)來正確縮小value
的類型。
每當我們有一個可能是假的值,但我們確信在特定情況下,該值一定是真的時,就應該使用invariant
。也就是說,該值是真的這一事實是一個不變量,如果發生該值是假的,則該不變量被違反,因此必須拋出錯誤。
由於message
參數在生產中被完全忽略,因此您可能希望在生產建置中將其從程式碼中完全刪除。若要了解如何執行此操作,請參閱最佳化部分。
declare const user : User | null | undefined ;
invariant ( user , 'The user is missing!' ) ;
user ; // If we get here, the type is narrowed to `User`
在此範例中, user
物件可能為null
或undefined
(即,假)。如果是這種情況,我們就會遇到不變違規,並且invariant
函數將拋出異常。否則,它只是返回,我們知道user
實際上指向一個用戶物件。
warning
warning ( value : unknown , message : string ) : void
value: unknown
是我們要檢查的值。如果它是假的,則會向控制台發出警告。
message: string
是將寫入控制台的警告訊息。
void
函數不會傳回任何內容。 如果指定的value
假,則warning
會向控制台發出警告並給予給定的message
。此警告僅在開發時發出。在生產中,此函數不執行任何操作。
每當我們想要在某些值是假的情況下發出僅開發警告時,就應該使用它,這應該有助於指導開發人員修復警告訊息中報告的非關鍵問題。
由於warning
在生產中不會執行任何操作,因此您可能希望從生產建置中的程式碼中完全刪除對此函數的呼叫。若要了解如何執行此操作,請參閱最佳化部分。
declare const mode : 'auto' | 'default' | 'slow' | 'fast' ;
warning (
mode !== 'auto' ,
'Mode "auto" has been deprecated. Please use "default" instead.' ,
) ;
在此範例中,如果mode
為'auto'
我們希望發出棄用警告。為此,我們需要傳遞一個假值,這就是為什麼我們傳遞mode !== 'auto'
,只有當mode
為'auto'
時,它才是假值。
在某些情況下,直接傳遞false
是有意義的。例如:
declare const languages : Language [ ] ;
declare const defaultLanguage : Language ;
declare const langName : string ;
let lang = languages . find ( ( { name } ) => name === langName ) ;
if ( ! lang ) {
warning (
false ,
`Language with name " ${ langName } " not found. Falling back to the default language.` ,
) ;
lang = defaultLanguage ;
}
assertNever
assertNever ( value : never ) : never
value: never
是用盡所有可能的聯合型別變體後的值。 never
表示函數永遠不會回傳;如果實際調用過,它只會拋出一個錯誤。 應該使用assertNever
來確保聯合類型的所有變體都已用盡。
如果value
的所有聯合變體都已用盡,則在使用value
調用assertNever
時不會出現編譯器錯誤,因為此時value
被認為是never
類型,並且在運行時,我們永遠不會達到調用assertNever
的點,這意味著不會拋出任何錯誤。
但是,如果尚未用盡所有聯合變體,那麼我們將使用never
之外的其他內容來調用assertNever
,因此會出現編譯器錯誤,提示類似以下內容
Argument of type 'x' is not assignable to parameter of type 'never'.
我們可以透過處理缺失的變體來修復它。您可以在 TypeScript 文件中閱讀有關聯合詳盡性檢查和assertNever
更多資訊。
declare const state : 'loading' | 'done' | 'error' ;
switch ( state ) {
case 'loading' :
return < Loading / > ;
case 'done' :
return < Done / > ;
case 'error' :
return < Error / > ;
}
在這個範例中,我們處理switch
語句內的所有可能狀態: 'loading'
、 'done'
和'error'
。
但是,如果將來我們再增加一個狀態(例如'pending'
怎麼辦?
switch
語句不處理'pending'
的事實將不會被偵測到。
解決方案是有一個default
情況,在該情況下我們斷言所有可能的狀態都已被處理。
switch ( state ) {
...
default :
return assertNever ( state ) ;
}
因此,當處理所有狀態變體時,我們不會遇到編譯時錯誤。但是,當我們新增新的'pending'
狀態時,我們將收到編譯器錯誤:
Argument of type 'string' is not assignable to parameter of type 'never'.
我們可以透過處理switch
內的'pending'
狀態來修復此錯誤。
正如您從這個範例中看到的, assertNever
在switch
語句中特別有用,我們希望確保始終處理所有可能的情況。
nonNull
nonNull < T > ( value : T | null | undefined ) : value is T
value: T | null | undefined
是我們要檢查是否為null
或undefined
值。 value is T
,這表示函數傳回一個布林值,指示傳遞的值是否既不是null
也不是undefined
。當傳回true
時,這會將value
的類型縮小為T
(即排除null
和undefined
)。 nonNull
是謂詞函數,用來檢查指定值是否為非 null,即既不是null
也不是undefined
。呼叫函數後,根據傳回true
或false
適當縮小value
的類型。
每當我們有一個可能為null
、 undefined
或兩者的值並且我們想要檢查它並適當縮小其類型時,就應該使用nonNull
。
此函數的名稱源自NonNullable
實用程式類型,該類型從類型中排除null
和undefined
。
declare const names : ( string | null ) [ ] ;
const nonNullNames = names . filter ( nonNull ) ;
// nonNullNames has type 'string[]'
在此範例中,我們有一個名稱數組,其中還可以包含一些null
元素。我們過濾數組中的所有非空元素並返回string[]
。
如果我們改用names.filter(x => x !== null)
,我們會返回非 null 元素,但類型仍然是(string | null)[]
因為 TypeScript 會看到我們傳遞給filter
函數因為只是返回一個boolean
,所以不會發生類型縮小。
我們建議使用babel-plugin-dev-expression
來剝離傳遞給invariant
message
參數,並完全刪除生產中對warning
的呼叫。
基本上,在生產中, babel-plugin-dev-expression
取代了
invariant ( value , 'Value is falsy!' ) ;
和
if ( ! value ) {
invariant ( false ) ;
}
所以message
參數被刪除。它還完全消除了對warning
呼叫。所以,像這樣的行
warning ( value , 'Value is falsy!' ) ;
被刪除。
非常歡迎請求請求。如果您打算引入重大更改,請先開啟相關問題,我們可以在其中討論您想要更改的內容。
請確保適當更新測試和自述文件。
麻省理工學院